Implementación de conjunto de valores específicos vs. uso de algún tipo de conjunto genérico con comprobaciones avanzadas

8

Actualmente estoy trabajando en una implementación establecida en JavaScript. Esto debería simular genéricos como se conoce de Java o C #. Necesito una versión mutable de eso (permite agregar / eliminar valores establecidos) y una inmutable.

Mi firma de constructor se ve así:

new GenericSet( 'number', [ 10, 20, 30 ] );

,

 // mutable set of mixed values (allows to add further values via "add")
 new MutableGenericSet( '*', [ 'foo', 42, {}, /./ ] );

o

// DataValues.prototype.equals will be used by the set for determining equality.
new GenericSet( { type: DataValue, valueComparison: 'equals' }, [ dv1, dv2, dv3 ] );

¿Solo GenericSet o un conjunto de implementación por tipo?

Inicialmente, mi propósito principal para esto era tener conjuntos de valores de un tipo. Por ejemplo, un DataValuesSet que solo aceptaría valores de datos. Entonces podría definir interfaces con funciones que requieren una instancia de DataValuesSet . No podía usar la herencia (y supongo que sería malo de todos modos), así que usaría composición y tendría una instancia GenericSet / MutableGenericSet internamente.

Un enfoque alternativo sería tomar siempre GenericSet e implementar y usar GenericSet.requireSetOfType( type )lo que arrojaría un error si el tipo del conjunto no fuera el requerido. Mi preocupación por hacerlo de esta manera es que las definiciones de mi interfaz se verían menos explícitas.

Tomar

/**
 * @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 );
    // ...
}

tal vez usar @param GenericSet(DataValues) dataValuespara documentar la segunda opción estaría bien? ¿Alguien ve más implicaciones con el segundo enfoque o hay alguna sugerencia alternativa? Para mí, el segundo parece más intuitivo y mi preocupación con el primero es que simplemente crearía más gastos generales con los constructores, mientras que ahora no puedo ver ninguna ventaja clara.

Daniel AR Werner
fuente
66
¿Por qué los genéricos son importantes en un lenguaje como JS que está tipado débilmente?
Yazad
1
Esto no es posible en un lenguaje como JavaScript, que se escribe de forma dinámica y débil. Simplemente use una variante JS escrita como TypeScript.
cabeza de jardín

Respuestas:

3

Solía ​​intentar resolver este tipo de problemas con JavaScript, que solo servía para complicar las implementaciones de ... Bueno ... cualquier cosa. Si no desea utilizar algo como el mecanografiado, documente lo que espera. Si las personas ignoran su documentación, entran en territorio desconocido.

No intente forzar una clavija redonda en un agujero cuadrado que cualquiera pueda moldear en un agujero redondo. Eso es JavaScript. Abrázalo. No luches, bebé. Documéntelo y simplemente vuelva a escribir el código.

Greg Burghardt
fuente
0

Yo diría que el primer ejemplo es más legible. No implica que se arroje un error para el conjunto incorrectamente escrito. Dice que esta función toma a DataValueSet. Ser explícito en su código agrega claridad.

GenericSet.requireSetOfTypeofusca la intención de la verificación de tipo en la función de impresión. Parece que está buscando elementos con tipo DataValue.

Hasen
fuente
La legibilidad no parece ser un argumento lo suficientemente fuerte para mí aquí. Se podría hacer la documentación perfectamente claro en ambos casos utilizando DataValuesSetvs GenericSet<DataValue>. Quizás en lugar de GenericSet.requireSetOfTypenombrar la función GenericSet.assertSetOfTypeo similar sería más claro.
Daniel AR Werner
0

Dadas las opciones que presentas, preferiría la primera solución, porque es más legible que la segunda. Pero, si realmente quiere hacer una solución de estilo JS, haga una función de constructor, ya sea que los objetos sean del mismo tipo o sean de tipo mixto ( MakeStrictCollectionvs MakeMixedCollection). En la función de constructor, que podría poner a prueba, si el tipo de cada miembro de su colección dada es del mismo tipo o no, y generará un error o devolver un objeto a partir de cada constructor, que tiene un atributo tipo adicional "type":"strict"vs "type":"mixed".


Aparte de eso:

Debe echar un vistazo a Typecript , que puede ser lo que está buscando. Y hay un paquete que parece satisfacer sus necesidades con colecciones genéricas .

Thomas Junk
fuente
-1 Para MakeStrictCollection vs MakeMixedCollection. Con respecto a los ejemplos de código anteriores, la printDataValuesfunción cambiaría para verificar que el objeto dado era instanceof StrictCollectiony que su tipo era DataValues. GenericSet.requireSetOfTypepodría ser exactamente eso; por lo tanto, su sugerencia parece ser simplemente un detalle de implementación del GenericSetenfoque.
Daniel AR Werner