#how important are generics?
1 messages · Page 1 of 1 (latest)
Always ways around generics
understanding them is pretty crucial in general when working with stuff, imo.
it's a useful tool, but it's not a universal tool. don't stuff it where it doesn't belong
cause im kinda intermediate in unity and when it comes to coding/c# experitse i thought i was kinda solid, i used composition and oop and knew abt several techniques like state machines using enums, when to use inheritance and when to use composition, but generics im trying to learn them and i js cant grasp when ill use them
how important it is to write them depends entirely on the systems you make
like im at a point where i can kinda see their power/usefulness but i js dont see a situation where ill use them ykwim
think of all the times you've used generics in those "predefined" functions
someone wrote those
like what kind of problem do i need to encounter to say "yeah generics fix this instantly"
if you need to write something like those, you'd need to write generics
without having composition or enums or polymorphism js do that
you don't. generics aren't a solution, generics are a tool
i mean an organizational solution
there's no problem you'd encounter where you'd say "yeah structs fix this instantly"
fair
or "yeah namespaces fix this instantly"
same thing here
this is just a tool in your toolbelt to make good systems/interfaces (in the sense of usage surface, not actual interfaces)
like what
the collections api
I use them in game dev for instance:
SpellSO //abstract
SpellProjectileSO : SpellSO
SpellAreaSO : SpellSO
Spell<T>: where T: SpellSO //abstract
SpellProjectile : SpellSO<SpellProjectileSO>
SpellArea : SpellSO<SpellAreaSO>
But this is with constraints
i see
so its like making an abstract class and then js making new classes that inherit it
but dont u lose the benefits of classes? like now SpellProjectileSO doesnt really have an identity, its js a Spell<T>
what if u have behaviour thats different for SpellArea like time active or smth?
Yeah so each derived class also wants a specific data (prevents casting too) which I add as a constraint. This helps extend the polymorphism too
theres no individualization
generics work alongside the rest of the type system, not against it
yeah ive had to cast SO's and found it to be a hardcoded fix ngl
problem with generics is you can't really serialize them with unity unless you do have constraints
like id have a base weaponSO and then a SworsSO thatd have things like swordthickness and whatnot thatd also inheir from weaponSO
and then after equipping the weapon id have to case the weaponSO to make it a swordSO to get its values
Depends on your implementation but you might not need generics there if you just reference stuff by its base class
i wouldnt really see them being used in initialization much anyways right? theyre more of a runtime thing
mostly i do, but when i have a script that has to use swordthickness and values that are in the swordSO id have to cast the org SO
Depends, usually you do want to be able to construct stuff on the editor if possible
prefabs, ect. But you can also do it in awake
yeah i see that happening
Generics for the most part reduce type checking similar to what chris said
yeah i just havent really internalized their use cases yet ngl
like you can make an inventory system with a bunch of inventory slot types using generics, or just make a bunch of slot classes and type check them
Still this wouldnt require generics, thats still just casting to a type. Maybe you would want to store it by a different sub class in this case if youre constantly casting
Simplest example of something that uses generics are lists. You are allowed to specify any type you want because the whole array part doesnt get affected by that
they js seem weird to me
Its not something you'll use frequently
It really boils down to a case where you want to store a value, but dont necessarily care what that value is
i see what u mean
yeah an inventory system would be great for that
(but the caller/consumer cares)
aight appreciate yall for the help
This is still pretty useful though, even though you can just make a bunch of standalone classes. Less code to copy that's for sure.
ngl to u, i dont see the benefit
like it might actually be a good system but i wouldnt have that grasped in my mind yet
ive dealt with classes and all their techniques basically since ive started so my mind is kinda hardcoded to thinking in that sphere
so when u show this to me im kinda js instinctively thinking "why dont i js use an abstract class as an identifier AND to hold base values ANY spell type would have?"
ik ur system is prob better but i js dont know how yet
i wont get it by talking abt it thats for sure ill have to encounter situations and such and go practical but still appreciate the help
Without the generics you could only declare the base SO type, but then you'd have to cast it inside of the class. Not that big of a deal but it's less of a strong typing if you do it that way.
But adding the generic constraint, you're saying that the declaration of the SO does have a strong type when extending the class with it.
But if you're coming from js it's probably not a big deal ;p
what im kinda confused here
in ur code
is the above part a different case and scenario than the below part?
here
ur showing the different case scenarios right?
The SOs are used as blueprints. They construct Spell<T> when it awakes and that data is inserted.
i see
Spell<T> basically just has the behaviors and the control logic
SO -> Damage, Speed, ect
so u have a base spellSO and other types of spells and their SO's that inherit from base and then have one generic class that handles the logic of ANY spell regardless of what exactly it is
right?
or did i get it terribly wrong or smth
but surely the logic of spell projectile is different than the logic of spell area
u cant really generalize them
Right, the base Spell<T> provides a lot of logic that the other spell classes may need like target and direction, but it makes no sense to say that Spell<T> has any logic involving speed, as only the Projectile/ProjectileSO cares about that
yeah exactly
Meanwhile SpellArea/AreaSO has maybe radius
yeah what happens here then?
do we have to include another class then inside the generic class?
no right that sounds bad
can we make functions inside the generic class that have constraints as well? like CastAreaDamage() can only be called if T is areaspell
Kinda, but that defeats some purpose. You want the base the share between all extended classes
then we're back to where we started
we'd now need to make a new class for each spells own unique logic
Like the base can have a bunch of abstract methods too yeah. ApplyDamage() may be used different between each of them
here's maybe another way to look at it:
generics are another way to reduce repetition, like inheritance or functions
functions reduce repetition where the logic is the same, but the parameters or calling context change
inhertiance reduces repetition where the core/base behavior is the same, but some details change, or behavior is added
generics reduce repetition where the structure and behavior are the same - the functions and variables and such - but the types change
ah i see
that makes sense
id obv need to use them more to actually grasp them but i get the core idea of them now
Like you can be fine by just casting everything, but you need to make sure that the data being implemented in these classes are correct, while the constraints that I'm doing here do prevent that.
yeah i get u
Because without the constraint here you could have a downcasted rather upcasted SO and you will error if you don't check the typing.
i heard abt the implemented type safety generics use which is another reason i was thinking abt them
anyways thanks for the help
eg```cs
struct WeightedElement<T> {
public float weight;
public T element;
}
public T WeightedRandom<T>(List<WeightedElement<T>> elements) { /* ... */ }
you wouldn't want to write this once for each thing you want to randomize, but you also wouldn't want an object return that you have to cast
Basically whenever you would find yourself writing the same function many times but with different parameter types, and the parameter type itself isn't important to the behavior of the function.
generics are useful because they allow the consumer of your code to be more specific than your code is (in a type-safe way)
i would add that once understand what abstraction truly is, you will find generics (or the pattern they represent (parametric polymorphism)) invaluable. They allow you to separate logic from the data it operates on.
an interesting observation is that you don't need generics for most things, strictly speaking
you could just have a List<object> and make sure you always put the right kind of thing in it
(and, indeed, that's what you had to do in Java in the olden days..)
One usecase for generics might for exmaple be a Singleton class you can inherit from that safely checks for instances and what not and let the user just use any class with type Singleton<MyclassName> to create a static instance at runtime out of it. So you have stuff like Onenable and awake inside that singleton class which will not be touched by the inheritance but rather use wrappers to be sure to always call the Awake() and after that everything your inheritance wnats to do at awake.