Difference between revisions of "Covariance and generics case study"

 
m
 
Line 31: Line 31:
 
item_list: THING[INTEGER]</e>
 
item_list: THING[INTEGER]</e>
  
To create a new covariant list class requires a class definition:
+
To create a new covariant thing class requires a class definition:
 
<e>
 
<e>
 
class
 
class

Latest revision as of 23:54, 12 April 2008

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 thing 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