Covariance and generics case study
These are some observations I had when comparing using generics and covariant redefinition in a project I'm working on. I had implemented it using generics but as I was progressing the usage of generics was becoming increasingly tedious and in the end, wasn't saving me any time or making things easier to understand.
Feel free to comment, edit, add.
Class text length and complexity is similar between generics and covariants equivalents
class THING[G] feature item: G put(new: G) is do item := new end
class THING feature item: ANY put(new: like item) is do item := new end
Differences in creating derived types To create a new generic class:
item_list: THING[INTEGER]
To create a new covariant list class requires a class definition:
class INTEGER_THING inherit THING redefine item end feature item: INTEGER end
Covariantly redefined classes are not cross-assignable like their generic counterparts:
class LIBRARY_A_INTEGER_THING inherit THING redefine item end feature item: INTEGER end
class LIBRARY_B_INTEGER_THING inherit LIST redefine item end feature item: INTEGER end
feature covariant_cross_assign(a: LIBRARY_A_INTEGER_THING) is local b: LIBRARY_B_INTEGER_THING do b := a -- Doesn't compile even though they are semantically equal. end
feature generic_cross_assign(library_a_list: THING[INTEGER]) is local library_b_list: THING[INTEGER] do library_b_list := library_a_list end
Generic parameterization geometrically increases text of type definition at usage points as inheritence depth increases:
params: ECDOMAINPARAMETERS [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP] pGen: ECKEYPAIRGENERATOR [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP] genParam: ECKEYGENERATIONPARAMETERS [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP] pair: ASYMMETRICCIPHERKEYPAIR [ECPUBLICKEYPARAMETERS [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP], ECPRIVATEKEYPARAMETERS [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP]] ecdsa: ECDSA_SIGNER [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP] ecdsa_verifier: ECDSA_VERIFIER [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP] keys: LINKED_LIST[ASYMMETRICCIPHERKEYPAIR [ECPUBLICKEYPARAMETERS [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP], ECPRIVATEKEYPARAMETERS [ECCURVE[ECFIELDELEMENTFP], ECPOINT[ECFIELDELEMENTFP], ECFIELDELEMENTFP]]]
Covariant redefinition greatly simplifies typing at usage points:
params: ECDOMAINPARAMETERS pGen: ECKEYPAIRGENERATOR genParam: ECKEYGENERATIONPARAMETERS pair: ECKEYPAIR ecdsa: ECDSA_SIGNER ecdsa_verifier: ECDSA_VERIFIER keys: LINKED_LIST[ECKEYPAIR]
You can "cheat" the generics solution and use the anchored type keyword 'like' as a shorthand for types. This is using the 'like' keyword as a macro instead of an anchored type. This shortens text but doesn't decrease complexity at the usage point and isn't using the keyword for what it was designed for.
c: ECCURVE[ECFIELDELEMENTFP] p: ECPOINT[ECFIELDELEMENTFP] e: ECFIELDELEMENTFP params: ECDOMAINPARAMETERS [like c, like p, like e] pGen: ECKEYPAIRGENERATOR [like c, like p, like e] genParam: ECKEYGENERATIONPARAMETERS [like c, like p, like e] pair: ASYMMETRICCIPHERKEYPAIR [ECPUBLICKEYPARAMETERS [like c, like p, like e], ECPRIVATEKEYPARAMETERS [like c, like p, like e]] ecdsa: ECDSA_SIGNER [like c, like p, like e] ecdsa_verifier: ECDSA_VERIFIER [like c, like p, like e] keys: LINKED_LIST[like pair]
Intermediate classes need to carry the generics of their suppliers and heirs causing geometric type definition increase
deferred class ECCURVE [G -> ECFIELDELEMENT] feature a: G b: G end
class ECPUBLICKEYPARAMETERS [G -> ECCURVE[I], H -> ECPOINT[I], I -> ECFIELDELEMENT] inherit ECKEYPARAMETERS [G, H, I] feature make_q_parameters(q_new: H params_new: ECDOMAINPARAMETERS [G, H, I]) is do end end
class ECKEYPAIRGENERATOR [G -> ECCURVE[I], H -> ECPOINT[I], I -> ECFIELDELEMENT] inherit ASYMMETRICCIPHERKEYPAIRGENERATOR [ECKEYGENERATIONPARAMETERS [G, H, I], ECPUBLICKEYPARAMETERS [G, H, I], ECPRIVATEKEYPARAMETERS [G, H, I]] ECCONSTANTS pair: ASYMMETRICCIPHERKEYPAIR [ECPUBLICKEYPARAMETERS [G, H, I], ECPRIVATEKEYPARAMETERS [G, H, I]] end
Covariants redefinition does not require generic pass-alongs
deferred class ECCURVE feature a: ECFIELDELEMENT b: ECFIELDELEMENT end
class ECPUBLICKEYPARAMETERS inherit ECKEYPARAMETERS feature -- Creation procedures make_q_parameters(q_new: ECPOINT params_new: ECDOMAINPARAMETERS) is do end
class ECKEYPAIRGENERATOR inherit ASYMMETRICCIPHERKEYPAIRGENERATOR redefine pair end ECCONSTANTS feature pair: ECKEYPAIR end