I am working on a set implementation in JavaScript currently. This should kind of simulate generics as known from Java or C#. I need a mutable version of that (allows for adding/removing set values) and an immutable one.
My constructor signature looks like this:
new GenericSet( 'number', [ 10, 20, 30 ] );
,
// mutable set of mixed values (allows to add further values via "add")
new MutableGenericSet( '*', [ 'foo', 42, {}, /./ ] );
or
// DataValues.prototype.equals will be used by the set for determining equality.
new GenericSet( { type: DataValue, valueComparison: 'equals' }, [ dv1, dv2, dv3 ] );
Just GenericSet or one set implementation per type?
Initially, my main purpose for this was to have sets of values of one type. E.g. a DataValuesSet which would only accept data Values. I could then define interfaces with functions that require a DataValuesSet instance. I could not use inheritance (and guess that would be bad anyhow), so I would use composition and have a GenericSet / MutableGenericSet instance internally.
An alternative approach would be to always take GenericSet and implement and use GenericSet.requireSetOfType( type )
which would throw an error if the set's type was not the required one. My concern with doing it this way is that my interface definitions would look less explicit.
Take
/**
* @param DataValuesSet dataValues
*/
function printDataValues( dataValues ) {
if( !( dataValues instanceof DataValuesSet ) ) {
throw Error( '...' );
}
// ...
}
vs.
/**
* @param GenericSet<DataValue>
*/
function printDataValues( dataValues ) {
// Throws error if dataValues is not a set or it it is a set with values of wrong type.
GenericSet.requireSetOfType( dataValues, DataValue );
// ...
}
perhaps using @param GenericSet(DataValues) dataValues
for documenting the second choice would be alright? Does anyone see any further implications with the second approach or are there any alternative suggestions? To me the, second one looks more intuitive and my concern with the first one is that I would just create more overhead with constructors while I can not see any clear advantage right now.
-
6Why would generics matter in a language like JS which is weakly typed?Y123– Y1232015年04月23日 23:28:29 +00:00Commented Apr 23, 2015 at 23:28
-
1This isn't possible in a language like JavaScript, which is both weakly and dynamically typed. Just use a typed JS variant like TypeScript.gardenhead– gardenhead2017年03月04日 02:10:00 +00:00Commented Mar 4, 2017 at 2:10
3 Answers 3
I used to try solving these sorts of problems with JavaScript, which only served to complicate implementations of... Well... Anything. If you don't want to use something like Typescript, document what you expect. If people ignore your documentation they enter uncharted territory.
Don't try to force a round peg into a square hole that anyone can mold into a round hole. That's JavaScript. Embrace it. Don't fight it, baby. Document it, and just get back to writing code.
I would say that the first example is more readable. It does not imply that an error is thrown for the incorrectly typed set. It says that this function takes a DataValueSet
. Being explicit in your code adds clarity.
GenericSet.requireSetOfType
obfuscates the intent of the type check in the print function. It looks like it is checking for items with type DataValue
.
-
Readability doesn't seem to be a strong enough argument for me here. You could make the documentation perfectly clear in either case by using
DataValuesSet
vs.GenericSet<DataValue>
. Perhaps instead ofGenericSet.requireSetOfType
naming the functionGenericSet.assertSetOfType
or similar would be clearer indeed.Daniel A. R. Werner– Daniel A. R. Werner2017年03月04日 16:56:26 +00:00Commented Mar 4, 2017 at 16:56
Given on the options, you present, I would prefer the first solution, because it is more readable than the second one. But, if you really want to do a JS-style solution, make a builder-function, whether the objects are from the same type or should be of mixed type (MakeStrictCollection
vs MakeMixedCollection
). In the builder function, you could test, whether the type of every member of your given collection is from the same type or not and throw an error or return an object from each constructor, which has an additional type attribute "type":"strict"
vs "type":"mixed"
.
Besides that:
You should take a look at Typescript, which may be, what you are looking for. And there is a package, which seem to suit your needs having generic collections.
-
-1 For
MakeStrictCollection
vsMakeMixedCollection
. In regard to the code examples above, theprintDataValues
function would change to verify that the given object wasinstanceof StrictCollection
and that its type wasDataValues
.GenericSet.requireSetOfType
could be exactly that - hence, your suggestion seems to be merely an implementation detail to theGenericSet
approach.Daniel A. R. Werner– Daniel A. R. Werner2017年03月04日 17:15:38 +00:00Commented Mar 4, 2017 at 17:15