Moment: hacer que el momento sea mayormente inmutable

Creado en 3 jul. 2014  ·  163Comentarios  ·  Fuente: moment/moment

Ha habido muchas discusiones sobre esto. Aquí está la propuesta:

Los siguientes métodos mutables se volverán inmutables en 3.0.0: utc , local , zone , add , subtract , startOf , endOf , lang , también en duration : add , subtract y lang .

Para empezar, todos los métodos se duplicarán con variantes methodNameMute . También necesitamos variantes inmutables llamadas methodNameImmute . A partir de 3.0, los métodos antiguos y sencillos comenzarán a usar la opción inmutable de forma predeterminada.

Lo que es discutible es:

  • ¿Debería lang hacerse inmutable?
  • en caso de que todos los captadores / definidores (incluidos get / set ) también se vuelvan inmutables
  • nombrar las versiones mutables e inmutables de los métodos
  • y, por supuesto, ¿deberíamos hacer el cambio o simplemente detenernos en la API inmutable?

Lo bueno es que hoy podemos hacer versiones inmutables de los métodos y decidir más adelante qué hacer. Si cambiamos, también significaría que la rama 2.x estaría disponible durante bastante tiempo después de que 3.x salga.

@icambron @timrwood @gregwebs @yang @lfnavess @soswow @langalex

Enhancement

Comentario más útil

Mi granito de arena es que deberíamos optar por la inmutabilidad total o no optar por la inmutabilidad total. Tener algunos métodos inmutables ( startOf , add ) y otros no ( year , get ) es confuso y los desarrolladores tendrán que realizar un seguimiento de cuáles son cuáles.

Todos 163 comentarios

Mi granito de arena es que deberíamos optar por la inmutabilidad total o no optar por la inmutabilidad total. Tener algunos métodos inmutables ( startOf , add ) y otros no ( year , get ) es confuso y los desarrolladores tendrán que realizar un seguimiento de cuáles son cuáles.

También preferiría todo lo inmutable por defecto. ¿Los captadores ya no son inmutables?

Estos son los grandes problemas que veo al cambiar a la inmutabilidad.

Pseudo-inmutabilidad

Debido a la naturaleza de javascript, nunca podremos tener una verdadera inmutabilidad.

Lo mejor que podemos hacer es crear una copia y luego mutar y devolver esa copia. Podemos envolver cuidadosamente todos los métodos públicos para asegurarnos de que siempre estamos copiando y mutando en lugar de simplemente mutando, pero eso no evita que alguien haga m._d = new Date() o incluso m._d.setHours(1) .

Estoy de acuerdo con @icambron , si pasamos a la inmutabilidad, debería ser un cambio completo. Cualquier método que pudiera cambiar una propiedad en un momento crearía una copia del momento y, en su lugar, realizaría un cambio en la copia.

Área de superficie de API

Lo desafortunado de cambiar a la pseudo-inmutabilidad es que se deben crear muchas apis nuevas si queremos seguir admitiendo la mutabilidad.

Antes, cambiar de mutar un momento a clonar y mutar un momento era tan simple como agregar un .clone() en el lugar correcto. Ahora, tendríamos que crear interfaces mutables para todos los establecedores, lo que aumenta considerablemente el área de superficie de la API.

Esto incluye los ~ 20 métodos de establecimiento, agregar / restar, local / utc / zone / tz, startOf / endOf, lang y cualquier otro método utilizado en complementos de terceros.

Preocupaciones por la memoria

Debido a que ahora estamos creando copias cada vez que queremos cambiar un valor, el uso de la memoria aumentará. Por supuesto, los nuevos momentos serán la recolección de basura, pero el costo adicional asociado con este cambio es algo a tener en cuenta.

Tendríamos que tener mucho cuidado para asegurarnos de no crear toneladas de clones desechables con métodos que utilizan otros incubadores.

Para rastrear qué métodos se están llamando, utilicé este pequeño contenedor de funciones.

for (var method in moment.fn) {
  moment.fn[method] = (function (fn, method) {
    return function () {
      console.log(method);
      return fn.apply(this, arguments)
    }
  })(moment.fn[method], method)
}

Ahora, al ejecutar un método, podemos ver cómo se pueden usar otros métodos en el prototipo. No todos estos métodos necesitarían clonar el momento, así que agregué comentarios sobre los que requerirían clonación.

moment().isSame(moment(), 'year')
isSame
clone        // clone
startOf      // clone
month        // clone
date         // clone
year         // clone
date         // clone
hours        // clone
minutes      // clone
seconds      // clone
milliseconds // clone
valueOf
local        // clone
zone         // clone
startOf      // clone
month        // clone
date         // clone
year         // clone
date         // clone
hours        // clone
minutes      // clone
seconds      // clone
milliseconds // clone
valueOf

Es decir, 21 copias que se crean y luego se descartan inmediatamente. Obviamente, podríamos optimizar esto utilizando algunos métodos internos que son mutables y solo exponen las versiones inmutables, pero aumentará significativamente la complejidad interna al tratar de mantener un registro de qué momentos aún necesitan clonación y cuáles no.

Preocupaciones sobre el rendimiento

Clonar un momento es mucho más lento que mutar un momento. Reuní un par de pruebas jsperf para esto.

http://jsperf.com/moment-cloning

http://jsperf.com/moment-cloning-2

Creo que la segunda prueba es una representación mucho mejor de las pérdidas de rendimiento cuando se cambia a pseudo-inmutabilidad. Si multiplicamos esos resultados por las 21 instancias de clonación mencionadas anteriormente, los tiempos de ejecución son mucho más lentos.

Estoy seguro de que podríamos optimizar la ruta para la clonación en un momento, pero tendríamos que hacerlo 50 veces más rápido para tener un rendimiento comparable. Estoy bastante seguro de que esto es imposible.

Resumen

El cambio a la inmutabilidad aumenta en gran medida la complejidad de las apis internas y externas y tiene importantes problemas de rendimiento y memoria. No creo que esos costos valgan los beneficios que proporcionaría la inmutabilidad.

Creo que las preocupaciones de rendimiento enumeradas aquí no son el punto:

En términos generales, se necesita un .clone () inicial para garantizar la corrección antes de realizar la mutación.

No podemos pretender que clone () no es necesario con la API actual. El caso principal aquí que es diferente es la realización de múltiples mutaciones secuenciales. Ese caso se aborda mediante la creación de una API de construcción de modo que todas las mutaciones se realicen como mutaciones en un solo clon.

¿Me faltan otros casos de uso comunes?

Mi problema original era específicamente sobre los métodos startOf y endOf . Por alguna razón, estos nombres para mí eran como "empezar de un mes" no "poner este momento en el comienzo de un mes". Los métodos como add y subtract están perfectamente bien en el sentido de la semántica. Está perfectamente bien agregar algo a un objeto sin crear uno nuevo.
Para mí, personalmente, cambiar el nombre de los métodos startOf y endOf a algo como toStartOf y toEndOf (como "mover este momento al comienzo de un mes") resolvería el asunto. En mi humilde opinión

@gregwebs Lo siento, quise decir set arriba.

No estoy de acuerdo con @soswow; Creo que debe ser coherente. De hecho, creo que toStartOf implica inmutabilidad aún más fuertemente, como si estuviera proporcionando una presentación alternativa a la toISOString . Más importante aún, creo que debemos ser capaces de hacer declaraciones como "Los establecedores de momentos mutan momentos" o "Los establecedores de momentos devuelven copias", no "bueno, para estos métodos ..."

Sobre las preocupaciones de @timrwood :

Que los objetos JS no sean realmente inmutables no me molesta. El punto es que la API proporciona un contrato inmutable. Por supuesto, el usuario puede hacer trampa jugando con las propiedades subrayadas, y la trampa es generalmente posible incluso en lenguajes donde la inmutabilidad es la forma principal de hacer las cosas.

Sobre el área de superficie y sobre el rendimiento: creo que necesitaremos usar los mutadores internamente para evitar usar toda esa CPU y memoria [1], así que tendremos que admitirlos en algún nivel. Entonces también podríamos exponerlos externamente, como setYear() , etc. Eso agrega un montón de superficie, pero en realidad no agrega mucha complejidad; para mutadores no explícitos, clonar externamente, mutar internamente.

Una forma de ver eso es que el usuario tiene que clonar su código, por lo que Moment también podría hacerlo por ellos. Eso presenta un problema con el encadenamiento en lugares sensibles al rendimiento, que podría ser combatido por una interfaz de constructor (según la idea de Greg) o permitiendo que el usuario simplemente use mutadores allí. El constructor agrega mucha complejidad [2], así que creo que prefiero las alternativas explícitas de mutación. Creo que la realidad es que la mayoría de las veces, Moment no se usa en situaciones sensibles al rendimiento, por lo que esas situaciones no tienen que ser las API más convenientes. Prefiero tener una buena API inmutable con una trampilla perf para cuando la necesite.

[1] Los chicos geniales en FP Land resuelven esto con _structural sharing_, pero eso probablemente no sea práctico aquí.

[2] Tradicionalmente, la gente crea constructores que son objetos separados, pero eso sería muy detallado aquí, ya que tendrías que copiar toda la API del setter. Solo escupir, pero una alternativa es que .chain() crea un momento de clonación que solo tiene una bandera isBuilding configurada. Luego, los clones internos se ignoran, simplemente devolviendo el objeto para la mutación. Luego build() desarma la bandera y devuelve ese clon. El problema es que necesitas que tus captadores griten asesinato sangriento si la bandera está puesta, o la gente terminará usando los Momentos encadenados pero no construidos que de repente son mutantes. Luego, debe diferenciar los captadores llamados externa e internamente. Blech. Otra alternativa es descomponer internamente la funcionalidad que necesita el constructor en un mixin y usarla tanto en el constructor como en Moment, pero eso probablemente no sea viable desde la perspectiva de la organización del código.

lo que funcionó para mí, fue agregar un parámetro adicional a las funciones, una bandera (me llamé yo mismo) para denotar mutabilidad, por defecto está en inmutable (devolver una copia o un nuevo objeto), y cuando detecto rendimiento, configuro la bandera en verdadero

este punto de vista resolvió muchos conflictos,
tener funciones con nombre similar que ejecutan casi el mismo código,
o tener que cambiar el nombre de la función y probablemente los parámetros cuando detecto puntos de rendimiento
en mis métodos públicos, comienzo el código llamando a las funciones con una copia y siguiendo las llamadas con la bandera en verdadero
con esto también puedo encadenar las funciones

en mi código trabajo con matrices de matrices, (como una tabla, matriz de filas)
así que tengo funciones para filtrar, unir, etc., que previamente devuelve una nueva matriz con el resultado, y detecto que para obtener el resultado final llamé varias veces a la misma función, ahora la primera llamada es crear una copia y no cambiar la matriz inicial, y las siguientes llamadas, trabajo con la misma fila de eliminación de matriz que no necesito

un ejemplo básico que podría estar aquí:
momento.add = función (medida, cantidad, auto) {
}

moment.add = function (medir, ammount, self) {
var $ momento = self? esto: esto.clone ();
// el código real
return $ moment;
}

Gracias a todos por sus 2 centavos :)

Para el protocolo, estoy de acuerdo con la última publicación de @icambron en todos los puntos.

Quedan dos grandes preguntas.

La más fácil es cuál debería ser la nueva API, dos opciones:
1.1 métodos con nombres diferentes (mutables e inmutables) year / setYear , startOf / setStartOf
1.2 o api del constructor chain().mutators().build() , que es la versión no pirateada de lo que propuso

La API del constructor definitivamente se ve más sexy, pero se debe tener cuidado de que los objetos no permanezcan en el modo de construcción por mucho tiempo, lo que agrega otra fuente de problemas para nosotros y los usuarios.

Ahora el problema difícil: migrar a la nueva versión. Veo dos opciones aquí:
Los desarrolladores de 2.1 tienen que reescribir su código (las expresiones regulares locas podrían funcionar en 1.1 y la solución de nivel AST para 1.2, dado que nadie usa year y month como los nombres de sus propios métodos). Python adoptó este enfoque, todos podemos ver el resultado, ¡nació un nuevo lenguaje!
2.2 opción para activar la API del constructor siempre activa (igual que ahora), y una forma de desactivarla para el nuevo código. Esto parece más _evolucionario_, pero la cantidad de confusión que causaría probablemente no valga la pena. Cada momento ahora tiene dos banderas: es mutable y, en caso de que lo sea, es estrictamente mutable (sin getters) o transicionalmente mutable (getters ok). Sin mencionar la recepción de objetos de momento en las funciones: debe verificar cuál es el modo, asegurarse de mantenerlo ... ¡qué lío!


Y ahora una idea loca que me vino ahora

Clon de copia en escritura

m = moment();
funcIDontTrust(m.clone());  // doesn't actually clone

function funcIDontTrust(m) {
  m.year(2005);  // perform the clone here
  console.log(m);
}

No estoy seguro de cuánto se puede recortar con este enfoque, dado que las instancias de momento son bastante ligeras. Además, ahora todos los mutantes deben realizar una comprobación.

Hay algunas formas de implementar con rendimiento variable en diferentes escenarios. La buena noticia es que es compatible con versiones anteriores y nos ahorraremos a nosotros y a nuestros usuarios un gran esfuerzo. Y creo que esto es más importante que reinventar la rueda.

No estoy seguro de lo que estamos ganando aquí.

Cambiar a inmutabilidad tiene un montón de costos asociados y tal vez me lo pierda, pero
Realmente no veo beneficios comparables.

Los principales beneficios parecen ser la preferencia del desarrollador. ¿Es todo esto para que los desarrolladores no tengan
pensar en la propiedad de un momento cuando se lo transmite?

No creo que el cambio a la inmutabilidad haga que los errores sean menos frecuentes, simplemente
cambiar el tipo de errores. El ejemplo de @ichernev incluso muestra el tipo exacto de errores que
superficie, que son igualmente difíciles de rastrear.

m = moment();
funcIDontTrust(m.clone());  // doesn't actually clone

function funcIDontTrust(m) {
  m.year(2005);  // perform the clone here
  // m is still in 2014
  // m.year(2005) created a clone but did not assign it to anything
  // it should be `m = m.year(2005)`
  console.log(m);
}

Aquí hay una lista de pros y contras entre mutabilidad e inmutabilidad. Si me perdí de algo
avísame y editaré este comentario.

| Inmutable | Mutable |
| --- | --- |
| Algunos desarrolladores lo prefieren | Algunos otros desarrolladores lo prefieren |
| Evita errores al pasar momentos | Evita errores al olvidar asignar momentos clonados |
| Con unas pocas docenas de nuevos métodos de API, también se admitirá la mutabilidad | Con el método .clone () existente, la inmutabilidad ya es compatible |
| | Un orden de magnitud más rápido |
| | Utiliza mucha menos memoria |

Creo que la inmutabilidad es útil, pero no creo que encaje bien en JavaScript. Creo que una interfaz inmutable puede tener sentido para un lenguaje como Elm, donde se espera inmutabilidad, pero para JavaScript, creo que se espera mutabilidad.

Muchas de las apis para typeof a === "object" incorporadas son mutables. Array#push,pop,reverse,sort,shift,splice,unshift todos cambian el contenido de una matriz en lugar de devolver una nueva matriz. Los 16 métodos Date#setX mutan su instancia.

Creo que estamos viendo a mucha gente quejándose de que los momentos son cambiantes, pero si cambiamos, creo que tendremos la misma cantidad de gente quejándose. Esto ya sucedió con los métodos eod/sod hace dos años.

Después de ver un montón de problemas antiguos sobre mutabilidad, creo que probablemente estoy sonando como un disco rayado aquí. En ambos lados, son los mismos puntos que se han planteado durante los últimos años. Solo quería asegurarme de que un argumento para mantener una api mutable estuviera representado en la discusión.

@timrwood esas son buenas comparaciones, pero está bastante claro que no se ha tomado el tiempo para comprender el caso de uso inmutable. Ya hemos comentado por qué las comparaciones de rendimiento que publicó suponen una API implementada de manera deficiente y no tienen sentido.

La comparación de errores tampoco es válida. Debido a que momentjs admite una API de encadenamiento, se podría esperar que sea inmutable.

var newM = m.year(2005) // wrong, these are both the same!

Entonces, tanto inmutable como mutable tienen el mismo problema en este momento. Podría evitarlo con la versión actual mutable si se deshiciera de la API de encadenamiento.

Por lo tanto, la API inmutable es preferible a la mutable porque puede pasar un momento de forma segura entre funciones. Con los momentos mutables actuales si paso un momento entre función tengo 2 opciones

1) La forma loca de errores (que probablemente sea la más común): investigue todo el código fuente para asegurarse de que no haya mutaciones no deseadas. Escriba pruebas unitarias para asegurarse de que no aparezcan mutaciones no deseadas.
2) De la manera sana (supongamos que todos están haciendo esto), programación defensiva: recuerde llamar a la función clone () antes de mutar en mi función.

Con la API inmutable, no tenemos que recordar llamar a clone () cada vez. En su lugar, debemos recordar llamar a la función API que nos permite evitar la clonación, pero esto es solo una optimización del rendimiento, no una cuestión de corrección.

está bastante claro que no se ha tomado el tiempo para comprender el caso de uso inmutable

Esa es una declaración injusta. Mi argumento es que veo los beneficios, pero no creo que superen los costos.

puede pasar un momento de forma segura entre funciones

no tenemos que recordar llamar a clon

¿No es este el caso de uso de la inmutabilidad? Si hay algo más que no me haya tomado el tiempo de entender, hágamelo saber, pero este parece ser el único argumento de los últimos años.

@timrwood sí, ese es todo el caso.

Pero no veo una señal de usted reconociendo que su caso _contra_ inmutabilidad (rendimiento horrible, promueve un tipo diferente de error que no está presente en la API mutable) no es válido.

Creo que deberíamos seguir con el punto de vista de ecmascript 5, y tal vez agregar una función que congele el objeto actual, o una bandera global que cree automáticamente objetos frezee

http://blogorama.nerdworks.in/preventextensionssealandfreeze/

tal vez un parámetro adicional en el constructor para crear un objeto congelado, porque un objeto congelado no se puede descongelar

@lfnavess Pensé en freeze antes de mencionar la copia en la escritura. El problema es que ... nadie lo usa / lo sabe, ni ayuda cuando no lanza una excepción (en modo no estricto); en realidad, crea errores locos para que usted los rastree.

@timrwood No creo haber dejado claro mi ejemplo. En la línea m.year(2014) // clone here quise decir que el momento interno en realidad haría un clon (asignaría más memoria) y m apuntaría a esa nueva memoria, automáticamente. Bueno, eso básicamente significa que clone() también debería asignar un poco de memoria de shell (algo que apunte a la representación de la fecha interna), simplemente no estoy seguro de cuánto se ganaría al hacerlo.

La creación de una versión a medias de clone , que clona solo la interfaz, y la capacidad de cambiar los datos subyacentes (desde el almacenamiento compartido hasta el específico de la instancia), realmente depende de lo caros que sean los objetos Date. La desventaja es que cada función necesita hacer this._storage._d lugar de this._d , y no estoy seguro de si eso superaría el beneficio.

No recibí ningún comentario sobre cómo lidiar con la migración de las bibliotecas / usuarios existentes del momento. Realmente no me gusta ninguna de las opciones que enumeré anteriormente.

La compatibilidad inversa es, en mi opinión, el argumento más fuerte en contra de esto. Si hacemos esto, solo tenemos que aceptar que es un gran cambio radical. Si no queremos aceptar eso, no deberíamos hacerlo.

Vale la pena mencionar re: perf que también hay algunas ventajas enormes que puede obtener de la inmutabilidad; no es un golpe de rendimiento monótono. Por ejemplo, puede almacenar en caché cosas a nivel de objeto, porque nunca cambiarán. También creo que deberíamos poder optimizar la basura viva de clone() ; AFAIK, implica clonar una fecha y copiar como cinco valores; Creo que deberíamos codificarlos como newThing._offset = oldThing._offset .

Editar, arg, no: los complementos también agregan campos (por ejemplo, aquí ).

Dado el fuerte deseo de compatibilidad con versiones anteriores y, sin embargo, mantener el peso ligero, creo que la mejor solución es bifurcar las fuentes de JavaScript (ya sea en las fuentes de este proyecto o comenzar un proyecto completamente nuevo). Hay espacio para más de 1 biblioteca de tiempo para Internet.

También: re: la idea de @ichernev sobre el uso compartido estructural, una posibilidad es usar la herencia de prototipos en lugar de envolver un objeto de estado compartido.

En WhoopInc hemos estado al acecho en esta discusión durante bastante tiempo. Dado que la discusión aquí parece ir en círculos, me tomé un tiempo este fin de semana para explorar cómo se vería una versión inmutable del momento con una API de construcción. (No tengo la intención de enviar un PR contra el momento a menos que me inviten a hacerlo, ya que estoy haciendo deliberadamente cambios más estridentes en la API de los que esperaría ver implementados en el momento mismo). Aquí está el resultado: https: // github. com / WhoopInc / momento-congelado

Solo llevo unas pocas horas, por lo que todo es realmente difícil, pero según los resultados de las pruebas, creo que la mayor parte de la funcionalidad del momento central está funcionando. Continuaré haciendo un seguimiento de esta conversación y agradecería recibir comentarios específicos de nuestra bifurcación en los problemas de nuestro repositorio.

Intentaré publicar algunos documentos actualizados en ese repositorio esta noche, pero básicamente dividí todos los métodos de establecimiento y mutación en un objeto de construcción separado. Por lo tanto, el uso de la API podría verse como frozenMoment("2014-07-21").thaw().subtract(1, "day").startOf("day").freeze().format("YYYY-MM-DD") . (Aunque en este ejemplo en particular sería más eficiente simplemente comenzar la cadena con un constructor en lugar de inicializar un constructor desde un FrozenMoment, usando frozenMoment.build("2014-07-21").subtract... )

FWIW, cuando comencé a usar el momento asumí que seguía los principios de FP y devolvería el mismo valor cada vez que llamo a una función:

var now = moment();
var yesterday = now.subtract(1, 'days');
var dayBeforeYesterday = now.subtract(2, 'days');

Por supuesto, no obtuve los resultados que esperaba. Esto me tomó por sorpresa como nuevo usuario.

Considere este pseudocódigo, que demuestra cómo habría esperado que se comportara el código:

var now = now;
var yesterday = now - 1day;
var dayBeforeYesterday = now - 2days;

Pero en cambio terminó funcionando así, lo que me resulta extraño:

var now = now;
var yesterday = now = now - 1day;
var dayBeforeYesterday = now = now - 2days;

Por ahora, aunque es bastante tedioso, simplemente .clone() todas partes.

var now = moment();
var yesterday = now.clone().subtract(1, 'days');
var dayBeforeYesterday = now.clone().subtract(2, 'days');

En mi opinión, Javascript es propenso a errores sutiles y creo que los principios de FP ayudan a minimizar esos errores.

Simpatizo con que esta sea una decisión difícil de tomar. Aprecio tu trabajo. Moment.js es asombroso.

+1 para 100% de inmutabilidad.

Honestamente, es un poco frustrante que no sea inmutable.

+1 para 100% de inmutabilidad en la versión 3

Definitivamente debería haber una API inmutable. Como usuario de otras bibliotecas de fechas (en particular, .NET DateTime y Joda Time / Noda Time), intuitivamente espero que el método add no mute el objeto de fecha.

+1 para inmutabilidad

+1 para 100% de inmutabilidad

Si la decisión se toma por inmutabilidad, estaría dispuesto a dedicar mi tiempo para que esto suceda. Tal vez emparejándose durante una videollamada. Me gustaría contribuir más al código abierto, pero necesito aprender a manejarlo.

Para mí, la inmutabilidad es preferible, pero debería haberse hecho desde el principio. Este es un cambio radical drástico. Una bifurcación de este proyecto que se centra en la inmutabilidad sería una mejor idea.

@dsherret Para eso está semver . Simplemente golpearíamos la versión principal.

Sin embargo, con un poco de esfuerzo podría introducirse como una opción de configuración: "¿Quieres que todo sea inmutable? Verdadero o Falso". El valor predeterminado sería falso.

Complemento de momento inmutable ymmv no oficial no admitido aquí: https://gist.github.com/timrwood/fcd0925bb779f4374a7c

¡Ja ja! Me sorprendió venir aquí mucho más tarde y descubrir que fui uno de los primeros defensores de una API más inmutable .. :)

Y sí, soy +1 por inmutabilidad para la próxima versión principal.

Otro +1 por mi momento inmutable por defecto.
Y aquí está mi brebaje 'imoment': https://gist.github.com/idrm/a91dc7a4cfb381dca24e (¡utilícelo bajo su propio riesgo!). Simplemente reemplace sus llamadas de momento () con imoment () y eso debería ser suficiente. Todas las llamadas a funciones estáticas moment.xyz () (por ejemplo, moment.min (), moment.max (), etc.) deben permanecer como están.

+ 1 millón de dólares

+1 para inmutabilidad

¿Puedo agregar un +1 a una sugerencia anterior de este hilo de discusión para cambiar el nombre de algunas de las funciones para que sean más fáciles de leer ("startOf" a "toStartOf", "add" to "plus", "month" to "withMonth ", etc.)? Es decir, asumiendo que toma la ruta inmutable por defecto. Utilizo mucho Joda Time y es muy fácil averiguar qué significa, por ejemplo, "date.withDayOfMonth (1) .withDayOfWeek (DateTimeConstants.MONDAY)".
Estos tampoco tienen que estar en la distribución principal JS; un complemento que los coloque en la parte superior del JS vainilla funcionaría igual de bien (diablos, estoy considerando seriamente escribir un complemento alineado con Joda Time para combinarlo con mi mod "imoment").

@ichernev , @icambron , ¿han tomado una decisión al respecto? ¿Los momentos serán inmutables en 3.0? Si es así, ¿cuándo espera que salga 3.0? Lo pregunto porque estoy considerando usar el momento congelado o escribir un envoltorio pequeño yo mismo, y me pregunto si debería esperar.

Para su información, el momento congelado ha estado principalmente en un patrón de espera recientemente: he transferido un montón de relaciones públicas de Momento ascendente, pero realmente no he trabajado en ninguna de las otras refactorizaciones que idealmente deberían ocurrir en esa bifurcación.

Dicho esto, frozen-moment debería funcionar muy bien si solo necesitas la configuración regional en inglés predeterminada. (Todo funciona para mis casos de uso y he mantenido la alta cobertura de pruebas unitarias de Moment). Las configuraciones regionales que no están en inglés están rotas porque no las actualicé después de migrar las API de configuración regional recientemente refactorizadas de Moment.

Una vez que tengamos una decisión para Moment 3.0, planearé trabajar un poco más seriamente en el trabajo de inmutabilidad en Moment, o en la bifurcación del momento congelado, según corresponda. Mi objetivo inicial sería corregir la compatibilidad con la configuración regional y mantener la paridad de funciones con la API de Moment 3.0.

+1 para inmutabilidad

+1 por inmutabilidad. ¿Qué pasa con el método format que también muta el objeto?

+1 por un momento inmutable.js
¿O quizás una bifurcación de moment.js? immutable-moment.js? Dado que esto definitivamente será un cambio radical.

: 100:
¡Haz los imootables!

+1 en estos días, la inmutabilidad es algo que espero en cualquier buena API de JS

: +1: Sí, por favor, nos gustaría mucho esto. Actualmente rociamos .clone () en todas partes.

+1 esto sería una mejora muy buena

: +1: inmutable todas las cosas

+1 para inmutable

Hazlo todo inmutable. Estoy harto de clonar cada variable de momento (ahora) antes de operar en la variable ahora y luego ahora se cambia nuevamente.

+1 para inmutabilidad

No hubiera esperado que startOf('day') mutara (aunque admitiré que está bien documentado si hubiera leído más detenidamente). Eso provocó un error divertido en mi aplicación.

Definitivamente estoy de acuerdo en que la mayoría de los operadores de moment.js son incómodos en su mutabilidad. mmnt.startOf('day') es súper intuitivo en el sentido de que muta mmnt .

Utilizo moment.js para casos de uso de tipo calendario con muchos bucles y comparaciones de fechas. He abordado los problemas de rendimiento con clone() y son atroces. Tener cierto control sobre qué clones y qué muta es esencial para mí y probablemente para otros.
Aunque tener clone() todas partes parece incómodo al principio, lo que hace es muy claro y hace que la refactorización para el rendimiento sea muy fácil para mí.

Si cada método comienza usando clone() internamente a ciegas por el simple hecho de tener una API más agradable, creo que nos habremos perdido el punto.

mi 2 ¢ :-)

@jdurand Prefiero mutar explícitamente que clonar explícitamente.

@dsherret No me importa explícitamente nada. Mi principal preocupación es no la clonación implícita, ya que es una operación muy costosa.
Alguien mencionó que los montadores tendrían que devolver una copia clonada y eso me asustó; Sería muy ineficaz.

@jdurand podría ser más ineficiente, pero creo que un clon implícito beneficiaría a la mayoría de las aplicaciones donde la diferencia entre objetos clonados y mutados no haría una diferencia notable en la experiencia del usuario final. Creo que la facilidad de los desarrolladores y tratar de evitar los errores del desarrollador deberían tener prioridad sobre unos pocos milisegundos guardados, ya que la mayoría de los desarrolladores no están realizando miles de operaciones de fecha a la vez. Para aquellos que lo son, tal vez podrían decir explícitamente que quieren mutar en lugar de clonar.

Nota al margen: con este cambio creo que se podrían realizar algunas mejoras de rendimiento ... por ejemplo, la clonación podría eliminarse haciendo referencia al objeto inmutable pasado y luego almacenar la operación que se realizará para este objeto (por ejemplo, add(1, 'days') ). El resultado solo se calcularía ejecutando las operaciones cuando se llame a algo como .toString() , .format() , .toDate() , .day() , etc. Eso sería un cambio dramático y podría no terminar siendo más rápido ... se necesitarían hacer algunas pruebas unitarias para comparar el rendimiento (además, podría haber otros problemas que no he considerado ya que nunca he mirado ningún código en moment.js aparte de cómo se clona).

@dsherret Me gusta el enfoque _builder _ / _ lazy_; En retrospectiva, probablemente debería haberse construido así desde el principio.
Como dijiste, creo que una bifurcación inmutable con compatibilidad API en mente sería la mejor.

2 centavos más:

  1. ¿Deberíamos estar realmente preocupados por el rendimiento, cuando el momento se construye claramente para la conveniencia más que para el rendimiento? Creo que analizar 'año' en m.add ('año', 1) es mucho más lento que clonar.
  2. A menos que haya una bifurcación total (nombre diferente, documento diferente), será un dolor de cabeza mantener 2 versiones. Creo que alguien inteligente debería tener una idea para generar moment.immutable.min.js y moment.min.js a partir de la misma base de código ...

¿Desde cuándo tenemos tanto miedo de romper los cambios? La versión actual es estable y la gente aún puede usarla sin refactorizar su base de código.

Mantener dos bases de código es una molestia, lo ralentiza y realmente no vale la pena solo para tener una versión mutable / inmutable.

Así que vayamos con un momento completamente inmutable, golpee la versión principal y terminemos con ella: bailarines:

Encontré este hilo cuando recién comencé a usar esta biblioteca, pero me he estado tirando de los pelos al depurar algunos códigos y lidiar con lo que para mí parecen ser efectos secundarios impredecibles de ser mutable. ¡Me encantaría ver una versión completamente inmutable de la biblioteca!

Enchufe desvergonzado: me cansé de esperar aquí una decisión firme. En los últimos días, resucité Frozen Moment y lo reescribí para que actúe como un complemento para Moment en sí. Felicitaciones a

Frozen Moment proporciona un tipo inmutable que funciona igual que Moment. Básicamente, la versión inmutable envuelve la funcionalidad de Moment y llama a .clone() cuando sea apropiado.

Para aquellos a los que les gustan las API de construcción, ¡los desafiaría a pensar en Moment como una implementación muy agradable de un objeto de construcción! Frozen Moment agrega el tipo inmutable central que todos queremos y un mecanismo para construir un Momento congelado inmutable a partir de un Momento mutable.

Para aquellos que solo quieren trabajar con una API inmutable conveniente, bueno, también tengo la intención de admitir eso. Todavía no he creado un constructor que construya directamente una instancia de Frozen, pero eso está en la lista TODO . A corto plazo, la solución es crear todo con moment().freeze() o moment.utc().freeze() .

Frozen Moment es, obviamente, una base de código joven, por lo que probablemente haya algunas asperezas, pero animo a todos los aquí presentes a que lo prueben y presenten problemas para cualquier cosa que no funcione de la manera esperada.

Oh, una cosa más: no estoy anunciando esto todavía, pero las instancias de Frozen Moment deberían "simplemente funcionar" con la mayoría de los complementos de Moment. Solo asegúrese de que todos los demás complementos de Moment se registren antes de Frozen Moment. Si encuentra un complemento que no funciona como se esperaba con Frozen Moments inmutables, presente un error y lo investigaré.

+1 en inmutabilidad

+1 para inmutable

¿Alguien miró el momento de implementación en la parte superior de Immutable JS ? Es una biblioteca optimizada para la inmutabilidad en JS, reutiliza partes inalteradas de un objeto inmutable, reduciendo los problemas de memoria.

¿Entonces los usuarios piden inmutabilidad pero el equipo central encuentra excusas para no hacerlo? :pag
Vamos chicos, este cambio es mucho más importante que reescribir el código en ES6 ^^ En su forma actual, la API es simplemente mala, un poco como JS Array, donde algunos métodos son inmutables (filtro, concat, etc.) pero algunos otros no lo son (revertir, ordenar) excepto que su restricción de compatibilidad con versiones anteriores es infinitamente mayor que para una biblioteca.

+1

una pequeña trampa que siempre me atrapa (y en mi humilde opinión, esta es una buena razón para la inmutabilidad):

var today = moment();
for (var i = 0; i < 7; i++) {
   week.push(today.subtract(i, 'days').format('dd').toUpperCase());
}

lamentablemente, esto no genera una matriz con los nombres de los días, sino algo extraño porque en realidad calcula la fecha de esta manera:

i = 0 = today -0;
i = 1 = today -0 -1;
i = 2 = today -0 -1 -2;
etc

así que tienes que refactorizarlo en esto:

var today = moment();
for (var i = 0; i < 7; i++) {
            if (i == 0) {
                week.push(today.subtract(0, 'days').format('dd').toUpperCase());
            }
            else {
                week.push(today.subtract(1, 'days').format('dd').toUpperCase());
            }
        }

@faebser excelente ejemplo

+1 para inmutabilidad

+1

@faebser me pasó esta mañana. La unión bidireccional + mutabilidad de Angular hace que sea un fastidio mantener las fechas de clonación para evitar modificar las actuales.

+1 por inmutabilidad, esto solo me costó un par de horas.

: +1:

+1 para inmutabilidad

Estoy un poco desgarrado por este tema.

El purista que hay en mí quiere gritar "¡+1 por inmutabilidad! Los objetos de momento son claramente del tipo ValueObject ".

Sin embargo, no podemos ignorar que moment.js es el decimotercer repositorio de JavaScript más popular en GitHub (y el número 24 en general), y que la búsqueda de "momento" en bower.io devuelve 111 resultados coincidentes. Incluso si podemos proporcionar a los creadores de aplicaciones una forma gradual de implementar una versión inmutable del momento, causará un gran lío entre sus dependencias.

@ichernev Quizás una sugerencia más humilde: ¿sería posible dedicar una pequeña parte de la página de documentación del momento a hablar de mutabilidad frente a inmutabilidad? Puede declarar brevemente su postura oficial sobre el tema y tal vez agregar un breve resumen de los argumentos, colocar un enlace a este hilo o, si desea una entrada de discusión específica, podría funcionar como una llamada a la acción.

En este momento, la página de documentación no menciona el término "inmutable". Buscar en Google "momento inmutable" te lleva a esta página, pero me tomó dos horas leer y todavía no estoy seguro de tu postura actual sobre el tema. Sería genial si el éxito principal de Google por "momento inmutable" diera una respuesta rápida sobre el futuro de la inmutabilidad en el momento :)

Para citar a @ jehoshua02 :
"Comprendo que es una decisión difícil de tomar. Aprecio su trabajo. Moment.js es increíble".

Esta es mi propuesta. En lugar de hacer que el momento base sea inmutable, agregue una fábrica moment.immutable . Sería una propiedad de la función moment y encerraría la misma firma API exacta que moment , pero inmutable.

Incluso podría ser simplemente una extensión prototipo de la fábrica mutable moment , usando las funciones de ese prototipo, pero clonando en su lugar.

EDITAR: Parece que WhoopInc / frozen-moment es exactamente lo que estoy buscando.

@thomasvanlankveld Los cambios importantes son para lo que están los números de versión principales. Cualquiera que utilice Bower y npm tendrá la opción de ceñirse al número de versión principal actual; No deberíamos preocuparnos por la compatibilidad con versiones anteriores aquí, excepto quizás aquellas personas que solo están sirviendo esto desde CDN. Pero si están usando momentjs de CDN, es probable que no estén tan interesados ​​en actualizar la biblioteca de vez en cuando.

Yo diría que tener inmutabilidad en la próxima versión principal, o la versión principal posterior, debería estar en la hoja de ruta.

Parece que también me encontré con este problema.

http://stackoverflow.com/questions/33002430/moment-js-formatting-incorrect-date

Así que estoy a favor de la inmutabilidad en todos los ámbitos.

+1 por inmutabilidad

Acabo de perder una noche con este comportamiento sorprendente e inesperado.
Otro +1 para inmutabilidad con un cambio de versión principal correspondiente para que quede claro.

+1 por inmutabilidad

+1 para total inmutabilidad.
La cantidad colectiva de horas perdidas debido a "a veces mutable, a veces inmutable" debe ser bastante grande.

Sí, lo digo en serio. ¿A quién le importa el rendimiento en una biblioteca de fecha y hora? ¿Como realmente? Supongo que el 99,9% de los usuarios no están haciendo nada que requiera un buen rendimiento, ni siquiera remotamente. Por lo general, maneja un par de citas o, en el peor de los casos, unos cientos. Los pocos usuarios que manejan millones de fechas por segundo pueden usar puntos API mutables optimizados.

La inmutabilidad es la única opción de diseño sensata. Hay varios estudios que muestran que la programación con tipos inmutables es mucho menos propensa a errores que con tipos mutables.

+1 por inmutabilidad. Esto me costó un par de horas.

Parte del problema es que los nombres de métodos como .startOf() no implican una mutación del objeto subyacente.

Me he topado con cuellos de botella en el rendimiento con Moment, por lo que puedo asegurarles que esto a veces puede suceder.

Sin embargo, no estoy convencido de que los momentos inmutables sean inherentemente menos eficientes y puedo imaginar algunos casos en los que serían más eficientes.

Este debate se zanjó hace mucho tiempo en el mundo de Java. Ganaron fechas inmutables y la implementación más popular (JodaTime) finalmente se convirtió en parte de la biblioteca estándar en Java 8.

Trabajar con LocalTime Java 8 ha sido uno de esos "¿Por qué no _siempre_ hicimos esto?" momentos. Rara vez evangelizo las tecnologías, pero, sinceramente, no veo ninguna ventaja en los objetos de fecha mutables.

Entonces, sí ... Odio que estos hilos se llenen de +1, pero la verdad es que alguien más va a crear una biblioteca de fechas JS inmutable si Moment no lo hace.

Recientemente me encontré con un nuevo módulo npm que pretende portar gran parte de la API de JodaTime (es decir, fechas de Java 8) a JS.

Esto traería cosas como inmutabilidad, LocalDate y LocalTime al nodo y al navegador.

Habiendo trabajado con estos conceptos en Java, todo lo demás se siente torpe y propenso a errores.

¿Enlace?

El viernes 11 de diciembre de 2015 a las 4:30 p.m. Andrew Schmadel [email protected]
escribió:

Recientemente me topé con un nuevo módulo npm que pretende portar gran parte de
la API de JodaTime (es decir, fechas de Java 8) a JS.

Esto traería cosas como inmutabilidad, LocalDate y LocalTime a
nodo y el navegador.

Habiendo trabajado con estos conceptos en Java, todo lo demás se siente incómodo
y propenso a errores.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/moment/moment/issues/1754#issuecomment -163964349.

Wout.
(escrito en el móvil, disculpe la concisión)

Como no he intervenido todavía, solo diré que estoy a favor de la inmutabilidad en el momento 3.0. Principalmente porque vengo de la escuela de pensamiento DDD, donde objetos como moment se considerarían _objetos de valor_ y, por lo tanto, se implementan mejor como inmutables.

Incluso si hay un impacto significativo en el rendimiento, sigue siendo lo correcto. Moment debe encajar de forma natural en los diseños de los demás. La API intuitiva triunfa sobre el rendimiento, y la mutación no es intuitiva en los objetos de valor (en mi humilde opinión).

También creo que el momento 3.0 debería eliminar su dependencia del objeto Date , pero esa es una discusión para un hilo diferente.

Estoy completamente de acuerdo con @ mj1856 aquí.

He estado usando Object.freeze en instancias de momento y esto generalmente ha logrado lo que necesitaba; excepto que acabo de descubrir que lo siguiente falla:

let now = Object.freeze(moment());
if (now.isSameOrBefore(anotherTime)) { // throws exception
}

La excepción:

TypeError: Can't add property _isValid, object is not extensible
 at valid__isValid (C:\git\quick-test\node_modules\moment\moment.js:93:24)
 at Moment.moment_valid__isValid [as isValid] (C:\git\quick-test\node_modules\moment\moment.js:2195:16)
 at Moment.isSame (C:\git\quick-test\node_modules\moment\moment.js:1945:44)
 at Moment.isSameOrBefore (C:\git\quick-test\node_modules\moment\moment.js:1962:21)

¿Se puede arreglar esto para que Object.freeze se puedan usar cuando se desee?

@wmertens Asumiría que esto es todo: https://github.com/pithu/js-joda

@ichernev , @ mj1856 , como no he estado involucrado en el desarrollo del núcleo del momento durante un tiempo y la inmutabilidad tiene un interés bastante significativo, me estoy retractando de mi postura anterior.

No estoy seguro de si fui el único bloqueador en esto, pero me siento cómodo avanzando con la inmutabilidad en 3.0.

@gabrielmaldi @wmertens Sí. Eso fue todo. Disculpas por mi comentario al límite de la incoherencia: claramente hice clic en el botón "Enviar" en una publicación a medio camino.

Para recopilar algunos de mis pensamientos inconexos:

  • Claramente, existe cierto interés en los objetos de fecha inmutables para JS. Hay bibliotecas de fechas inmutables maduras en varios otros lenguajes, y hay mucho impulso general hacia los objetos inmutables en JS ( immutable.js tiene 10,500 estrellas si eso es una indicación). Por lo menos, creo que esto merece una prueba de concepto.
  • A pesar de este interés, parece que se ha escrito muy poco código. js-joda parece ser el primer intento serio de escribir una biblioteca de fechas inmutable para JS.
  • Los momentos inmutables serían un gran cambio radical, que plantea algunas preguntas filosóficas. Si bien odiaría perder el apoyo de la gran comunidad de MomentJS, no sería necesariamente algo horrible para aquellos de nosotros que estamos interesados ​​en fechas JS inmutables para hacer una ruptura limpia y contribuir a js-joda en lugar de intentarlo para impulsar un cambio bastante radical en Moment (una biblioteca madura con una base de usuarios grande y establecida).
  • Aparte: js-joda es todavía muy joven y no está claro cuáles son los objetivos e intenciones del autor para la biblioteca. En particular, debe elegir una licencia, y es posible que queramos considerar si las necesidades del desarrollador JS típico se cubrirían con una reimplementación fiel de Joda Time o JSR-310.

+1 para una inmutabilidad, y el código más sano que resultará.

Será un gran esfuerzo, así que un más sincero agradecimiento a quienes estarán (y han estado) logrando que esto suceda.

Moment se usa lo suficientemente ampliamente como para que creo que sea factible ir con algo que se acerque a lo siguiente, suponiendo que se implemente de manera similar a https://github.com/WhoopInc/frozen-moment de @butterflyhug

3.x: inmutable como una opción, predeterminado en falso, y tener un indicador establecido en la exportación de momento global que se establecería en verdadero; console.warn en la carga de la biblioteca (en modo dev)
4.x: inmutable como una opción, predeterminado en verdadero, el indicador aún está disponible para establecerse como falso; console.warn acerca de la programación para 5.x (en modo dev)
5.x: inmutable como único camino

Tenga una página al principio y al centro que describa la visión de la inmutabilidad a largo plazo, digamos, un lanzamiento importante al año a lo largo del esquema 3.x / 4.x / 5.x que presenté, y creo que daría un resultado razonable. cantidad para que cualquier persona afectada actualice su código.

Algunas observaciones:

  1. Construí WhoopInc / frozen-moment con la esperanza de que un grupo de personas aquí pudiera estar dispuesto a construir cosas con él, como una forma de encontrar puntos problemáticos en el ecosistema de momento donde la inmutabilidad rompería los complementos, etc. Hasta ahora, pocas personas han hecho eso. , lo que me ha hecho menos ansioso por trabajar en momentos congelados y / o evangelismo comunitario para ayudar a los autores de complementos a soportar momentos inmutables.

Dicho esto, todavía estoy dispuesto a ayudar a corregir los errores que las personas encuentran cuando usan el momento congelado, independientemente de si esos errores son míos o si están en un complemento de otro momento que nunca consideró la posibilidad de que los momentos se vuelvan inmutables. Simplemente presente los problemas en el momento congelado y echaré un vistazo. Y sigo pensando que un esfuerzo comunitario en torno a algo como el momento congelado podría ayudarnos a comprender y aliviar el dolor de una transición a momentos inmutables.

  1. Si moment implementa la inmutabilidad en 3.0, sería bastante sencillo para alguien escribir y mantener un contenedor para implementar la API mutable moment 2.x sobre la API inmutable 3.x. Conceptualmente, esto en realidad se parecería mucho a un momento congelado: en todas partes ese momento congelado implícitamente clone() s, esta envoltura de mutabilidad cambiaría implícitamente su referencia interna a un nuevo valor de momento inmutable. Esto también podría ayudar a facilitar la transición para las personas que usan moment en grandes bases de código.
  2. Estaría dispuesto a ayudar a pensar en problemas potenciales e implementar la inmutabilidad en el momento 3, si lo desea.
  3. js-joda portará directamente JSR-310 a JavaScript usando una licencia BSD .

@butterflyhug - ¡Gracias por construir el momento congelado! Me emocioné cuando encontré eso, pero me preocupé por introducir una dependencia de mi proyecto al momento congelado, dado que si el soporte se abandonaba, cambiar de un momento inmutable a uno mutable sería un gran trabajo en mi código. Si su objetivo era obtener comentarios y los está apoyando activamente, entonces me siento más cómodo haciéndolo. :-)

No sé cuántas otras personas podrían haber tenido los mismos procesos de pensamiento.

Tengo curiosidad si la gente aquí piensa que la inmutabilidad debe explorarse junto con la noción de romper la dependencia del objeto Date (o incluso agregar algún tipo de evaluación perezosa) por razones de rendimiento.

Sugeriría tomar las cosas paso a paso, @schmod. Esto ya es (aparentemente) un gran cambio.

@RobertMcCarter Sí, planeo admitir el momento congelado en el futuro previsible, a menos que / hasta que se implemente alguna opción de inmutabilidad en la biblioteca central, en gran parte porque lo estoy usando personalmente para algunas cosas que espero que sean manteniendo por un tiempo. Dicho esto, mis casos de uso no abarcan todo el ecosistema de Moment, por lo que confío en los comentarios y el uso de otras personas para ayudar a identificar lo que es importante.

+1 para la inmutabilidad, después de media hora de averiguar qué sucedió con mi aplicación después de usar endOf () por primera vez. De acuerdo, no leí los documentos con cuidado, simplemente asumí que un método con ese nombre devolvería el final del mes, por ejemplo, y dejaría la instancia de momento sin afectar. Para ser honesto, es una sorpresa y me parece ridículo que no suceda de esta manera o tal vez mi cabeza esté demasiado acostumbrada a los enormes beneficios, en mi opinión, de tener una API casi inmutable.

+1 para inmutabilidad :)

No me importa la inmutabilidad, ¡deja en paz esta excelente biblioteca!

@ es6Test ¿Por qué motivos no está de acuerdo con la inmutabilidad? ¿Tiene alguna razón concreta además de la resistencia al cambio?

+1
Creo que facilitará el uso de la biblioteca si fuera inmutable, mi código está lleno del método .clone () y, en algún momento, la mutabilidad provoca errores muy difíciles de encontrar.

+1 Por favor, más inmutabilidad ^ _ ^

@danpantry Después de crear algunas aplicaciones más, cambié de opinión. Preferiría la inmutabilidad.

Pero me gustaría tener algunas vars mutables, a menudo me gusta agregar días a momentos y no quiero tener que crear más vars para mantener el resultado.

@ es6Test ¿ Solo usa let si _realmente_ no te gusta?

let date = moment()
// with immutability
date = date.add(5)

También estoy a favor de la inmutabilidad. Esa es la única característica de la biblioteca datetime de Python que realmente la hace brillar. Puede lanzar objetos sin preocuparse de que algo los modifique, al igual que con las cadenas de caracteres.

En el mundo de React / Redux, la inmutabilidad es muy importante. Ya me encontré con algunos problemas complicados porque el momento no es intrínsecamente inmutable. El rendimiento es irrelevante aquí, ya que puede mitigarse. La biblioteca ImmutableJs de Facebook demuestra que se puede hacer inmutable sin sacrificar el rendimiento.

También haré +1 en inmutabilidad hasta el final. No obtienes ningún beneficio de la inmutabilidad hasta entonces, por lo que no tiene sentido hacerlo a mitad de camino.

La inmutabilidad y la programación funcional se utilizan ahora más que nunca (y me encanta). Ofreceré mi propio tiempo para contribuir a esta iniciativa. Colaboradores, por favor contácteme y déjeme saber cómo puedo ser de ayuda.

El equipo quería dar una actualización sobre esto ya que hemos tenido mucho interés.

En este momento, queremos que sepa que hemos escuchado sus inquietudes. Todo el equipo de mantenedores está de acuerdo en que si escribiéramos la biblioteca desde cero, elegiríamos hacerla inmutable. Sin embargo, no es así en este momento.

Tal como está, tenemos 4 millones de descargas de NPM al mes, junto con un número incontable de usuarios que confían en obtener momento a través de otros canales. Todos estos usuarios tienen un código que espera que el momento sea mutable como lo es hoy. Además, tenemos muchos complementos que dependen de que el momento sea mutable.

El código es bastante fácil de escribir, pero las necesidades de soporte de este tipo de cambio son difíciles de asumir como un equipo pequeño que hace esto en nuestro tiempo libre. Dicho esto, estamos dispuestos a considerarlo. Sin embargo, nos preguntamos:

  • ¿Por qué el complemento de momento congelado no satisface sus necesidades?
  • ¿Solo necesita una API inmutable (una API que siempre devuelve un clon) o, por alguna razón, necesitamos realmente no mutar los objetos internamente?
  • ¿La adición de una segunda API inmutable al código actual satisfaría sus necesidades?

El problema con el complemento de momento congelado es que es de suscripción, no de exclusión. Cada
moment () necesita un .freeze () para que sea inmutable.

El punto de la inmutabilidad es que cuando tengo el objeto X, sé que
a menos que lo haga explícitamente mutable, debe ser impermeable al cambio.
Cualquier función pública que me permita cambiar un objeto internamente sin
la mutabilidad explícita es problemática.

Creo que una solución alternativa es hacer varias cosas:

  1. Agrega una segunda API inmutable al código actual
  2. Tener una configuración de momento global () donde si está configurado en modo inmutable, todos
    Las instancias moment () creadas son inmutables, si se intenta una llamada mutable,
    no mutará y en su lugar error con el mensaje apropiado para usar inmutable
    llamadas api.

Eso creo que satisfará a todos. ¿Qué piensas?

El lunes 23 de mayo de 2016 a las 12:11 p.m., Maggie Pint [email protected]
escribió:

El equipo quería dar una actualización sobre esto ya que hemos tenido tanto
interesar.

En este momento, queremos que sepa que hemos escuchado sus inquietudes. los
Todo el equipo de mantenedores está de acuerdo en que estábamos escribiendo la biblioteca desde el
desde cero, optaríamos por hacerlo inmutable. Sin embargo, no es as como
es ahora mismo.

Tal como está, tenemos 4 millones de descargas de NPM al mes, junto con una
incontable número de usuarios que confían en obtener el momento a través de otros
canales. Todos estos usuarios tienen un código que espera que el momento sea mutable como
es hoy. Además, tenemos muchos complementos que dependen del momento
mudable.

El código es bastante fácil de escribir, pero las necesidades de soporte de este tipo de
el cambio es difícil de asumir como un equipo pequeño haciendo esto en nuestro repuesto
tiempo. Dicho esto, estamos dispuestos a considerarlo. Sin embargo, nos preguntamos:

  • ¿Por qué el complemento de momento congelado no satisface sus necesidades?
  • ¿Solo necesita una API inmutable (una API que siempre devuelve un
    clon), o por alguna razón necesitamos realmente no mutar internamente el
    ¿objetos?
  • ¿Agregar una segunda API inmutable al código actual cumpliría con su
    ¿necesidades?

-
Estás recibiendo esto porque hiciste un comentario.
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/moment/moment/issues/1754#issuecomment -221062274

Eric Lau de la cuenta de Gmail.

Gracias por responder @maggiepint.

  1. Algunos problemas con el complemento de momento congelado: no es el predeterminado, requiere trabajo adicional para su uso, hay menos posibilidades de que se mantenga activamente, mi suposición es que tiene un impacto en el rendimiento (probablemente uno muy pequeño) sobre algo que estaba construido como inmutable. Creo que el mayor problema es olvidar usarlo, especialmente en proyectos más grandes con muchos ingenieros.
  2. La API debe estar libre de efectos secundarios. Devolver un clon es bueno, pero si también modifica el objeto original, eso sería un efecto secundario. El siguiente código no debe modificar el inicio al declarar el final:
start = moment();
end = start.add(10, 'minutes');
  1. ¿Te refieres a tener funciones como 'immutableAdd' además de 'agregar'? Si es así, técnicamente lo haría, especialmente si crea un contenedor para usar funciones inmutables con los mismos nombres:
import "moment/immutable";
start = moment();
end = start.add(10, 'minutes'); // immutable version of add

En mi opinión, este enfoque se presta a una actualización elegante para aquellos que desean usar la API inmutable; el código existente seguirá funcionando, nadie se verá obligado a ingresar y requiere menos cambios para aquellos que quieran usar la API inmutable.

Tenemos toda la intención de hacer que los efectos secundarios del código sean gratuitos. El patrón básico sería conectarse a las funciones actuales, hacer que llamen a clonar y luego operar en ese clon.

Sin embargo, técnicamente, si está creando un código verdaderamente inmutable, los objetos deben construirse con valores que no cambiarán. Sin embargo, hacerlo aumentaría la dificultad para realizar este cambio. Es mucho más fácil llamar a clonar y luego hacer lo que estábamos haciendo antes.

Secundo la idea de Drew:

importar "momento / inmutable";
inicio = momento ();
end = start.add (10, 'minutos'); // versión inmutable de add

Eso sería genial, ya que es una opción de exclusión inmutable y no hay cambios en
nombres de funciones.

El lunes 23 de mayo de 2016 a las 12:53 p.m., Maggie Pint [email protected]
escribió:

Tenemos toda la intención de hacer que los efectos secundarios del código sean gratuitos. Lo básico
El patrón sería engancharse a las funciones actuales, hacer que llamen a clonar,
y luego operar en ese clon.

Sin embargo, técnicamente, si está creando un código verdaderamente inmutable, los objetos
debe construirse con valores que no cambien. Hacerlo lo haría
Sin embargo, aumenta la dificultad para realizar este cambio. Es mucho más fácil
llamar a clon y luego hacer lo que estábamos haciendo antes.

-
Estás recibiendo esto porque hiciste un comentario.
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/moment/moment/issues/1754#issuecomment -221076796

Eric Lau de la cuenta de Gmail.

@ ericlau-solido

  1. Tener una configuración de momento global () donde si está configurado en modo inmutable, todos
    Las instancias moment () creadas son inmutables, si se intenta una llamada mutable,
    no mutará y en su lugar error con el mensaje apropiado para usar inmutable
    llamadas api.

Esto se romperá si 2 bibliotecas en la página esperan diferentes comportamientos de momento. Por ejemplo, usa datepicker, que espera un momento mutable, y su propio código espera uno inmutable; no funcionará.

Tener api inmutable (un momento congelado)

Esto tampoco es perfecto, porque ningún complemento de momento funcionará con él. En realidad, no hay forma de introducir inmutabilidad Y mantener todos los complementos existentes en funcionamiento. Los complementos no funcionarán en absoluto, o no funcionarán con momentos inmutables, antes de que alguien dedique el tiempo a hacerlos funcionar.

importar "momento / inmutable";

Básicamente, se trata de proponer una biblioteca diferente con una interfaz similar. Claro, no romperá el código, pero probablemente causará confusión y hará que algún proyecto tenga las 2 versiones instaladas (por ejemplo, datepicker tomará la versión mutable y tu código tomará la inmutable).

La mejor opción es hacer una API como la actual, pero con objetos inmutables. Una bifurcación podría estar en orden. Después de todo, esa es la forma del software libre.

La opción "agregar una segunda API / publicar un submódulo" sería la mejor opción para la compatibilidad, porque los desarrolladores podrían actualizar su código de forma incremental. Si es posible, el significado de moment() (a través de import moment; en module-land, o el moment global en la compilación del navegador) no debería cambiar en absoluto, porque hay un tonelada de código heredado por ahí.

En mi opinión, una solución que permitiera lo siguiente sería ideal:

import moment from 'moment';
import {immutable as immoment} from 'moment';

var a = moment(); // mutable moment
var b = moment().immutable(); // immutable moment
var c = immoment(); // also an immutable moment; shorthand

No es una biblioteca diferente, pero sí, tiene dos tipos de momentos separados y distintos. Suponiendo que los objetos de momento mutables e inmutables comparten una cantidad significativa de código "bajo el capó", el tamaño de la biblioteca no necesitaría aumentar mucho para los desarrolladores que necesitan usar ambas sintaxis. Si una aplicación solo usa una sintaxis, la agitación de árboles podría usarse para producir una compilación optimizada.

Bifurcar la biblioteca podría duplicar el tamaño del código que la mayoría de los desarrolladores necesitarán cargar, lo que no sería deseable para la mayoría de las aplicaciones web.


No creo que sea una buena idea suponer que los complementos funcionarán con momentos inmutables "listos para usar" y no consideraría que ese sea un requisito razonable.

Tampoco creo que sea un requisito / suposición razonable que las API mutables e inmutables sean idénticas. Debemos esforzarnos para que la ruta de actualización sea lo más fluida posible, pero no debemos encerrarnos en sintaxis incómodas.


También creo que hay mucho espacio para el debate / discusión sobre cómo se vería la API "inmutable". ¿Patrón de constructor? ¿Creación de instancias de constructor? Objeto de valor? Implementar la API actual, pero ¿algún método "setter" devuelve un clon?

Mi única solicitud es que la nueva API sea clara e inequívoca sobre el tipo de momento en el que estamos trabajando. En mi opinión, freeze falla esa prueba y ofrece poca protección más allá de llamar a clone() cada vez que paso un momento.

Básicamente, se trata de proponer una biblioteca diferente con una interfaz similar. Claro, no romperá el código, pero probablemente causará confusión y hará que algún proyecto tenga las 2 versiones instaladas (por ejemplo, datepicker tomará la versión mutable y tu código tomará la inmutable).

No es una biblioteca separada, solo una envoltura delgada alrededor de la misma biblioteca. Solo sería necesario instalar una versión de moment. Puede importar 'momento / inmutable' y el selector de fechas puede importar 'momento' en el mismo proyecto sin problemas.

Podría haber problemas al interactuar con complementos que toman o regresan un momento si no se han actualizado para manejar momentos inmutables.

Digamos que pasa un momento inmutable a un complemento que, en la actualidad, lo trata como mutable. Hasta que se actualice el complemento, debería haber una forma de convertir a mutable antes de que se le dé un momento al complemento. Idealmente, quedaría obsoleto después de que los encargados del mantenimiento del proyecto tengan algo de tiempo para apoyar la inmutabilidad. Probablemente también debería haber una forma de detectar la inmutabilidad (para los autores de complementos).

Por otro lado, una biblioteca que se actualiza para usar la interfaz inmutable y devuelve un momento inmutable a los usuarios, puede despistar a aquellos que no usan la inmutabilidad y no esperan un momento inmutable. Creo que esto también se puede manejar mediante un método de conversión obsoleto. Los complementos deben devolver un momento del mismo tipo que se pasa.

@maggiepint sí, entiendo tu punto, pero creo que podría ser un salto demasiado grande para dar. Personalmente, estaría bien con un enfoque que simplemente clone está detrás de la cortina. Especialmente mientras se resuelven los problemas.

@tacomanator, eso es lo que quiero hacer también. Rehacer todo para que sea realmente inmutable internamente no es terriblemente sostenible.
Sin embargo, no sabía si por alguna razón la gente QUERÍA eso.

@schmod ¿Podría explicar brevemente por qué no cree que freeze sea ​​una API clara e inequívoca?

Si el nombre de la función es demasiado lindo, me complacería considerar un argumento para cambiar el nombre de los métodos de Frozen Moment como un problema en ese repositorio. Por otro lado, si no cree que debería ser posible convertir de mutable a inmutable (y viceversa), sospecho que eso podría generar alguna discusión aquí, aunque tenga en cuenta que también estaría dispuesto a tomar Frozen Moment en esa dirección si obtenemos un consenso aproximado de que esa sería una mejor API.

@maggiepint ¿Estoy en lo cierto al leer "agregar una segunda API inmutable al código actual" como básicamente un paquete de parte o todo Frozen Moment con la biblioteca central? Si fuera útil, me complacería ayudar a migrar Frozen Moment o algunas de sus ideas a la organización del momento (ya sea como un complemento oficial o como parte de la biblioteca principal) y ayudar con su mantenimiento en ese nuevo contexto.

@butterflyhug Estás diciendo exactamente lo que estaba pensando @ichernev . Se estaba inclinando hacia el complemento oficial que se envió con la biblioteca. ¿Quizás podríamos coordinar esto en Gitter en algún momento? Tengo que estar ausente durante tres días por negocios, así que tendré disponibilidad limitada. El resto de los chicos debería estar cerca.

@mariposas

Creo que freeze es un buen nombre, simplemente apesta tener que recordar usarlo después de cada invocación de un momento.

También creo que import 'moment/immutable' tiene los mismos problemas, es fácil olvidarlo.

Honestamente, estás siguiendo a semver, creo que el enfoque correcto es hacer que todo se use inmutable _de forma predeterminada_ y lanzar este cambio como su propia versión principal, con un plan para dejar de admitir versiones anteriores después de un período de tiempo (¿12 meses?). Las nuevas funciones / correcciones podrían fusionarse en ambas pistas, inmutables y mutables, con un plan de migración dado a los usuarios que usan la versión mutable.

Después de los 12 meses antes mencionados, las versiones anteriores seguirían funcionando, pero no recibirían ningún TLC.

Por supuesto, esto es una gran cantidad de gastos generales, pero creo que sería mejor hacer este cambio correctamente que intentar manipularlo en aras de la compatibilidad con versiones anteriores. También hace que el cambio sea mucho más complicado, lo que puede disuadir el interés del equipo de desarrollo central. No se.

Otro posible inconveniente de este enfoque es que los usuarios utilizan este script de una CDN y no especifican una versión explícita (por el motivo que sea), lo que puede provocar que sus sitios se rompan si se lanza una API compatible con versiones anteriores. Todo lo que puedo decir es "te lo dije", pero entiendo que esto puede no ser un riesgo aceptable por el momento.

Tener dos versiones de la misma biblioteca solo sería un problema si confía en un objeto global y realmente no hay una forma ordenada de evitar eso que no sea simplemente continuar usando freeze() .


TLDR parece que el problema que está tratando de resolver se resuelve con semver, que ya está usando. ¿Por qué no utilizarlo como debería? Versión principal para cambios importantes. La única ocasión en que esto se rompe es cuando confía en una variable moment global y usa un CDN, pero cualquier cambio que hagamos aquí lo romperá de todos modos.

Mi voto también está en semver e inmutable versión 3.0.

No me opongo al nombre freeze , pero me parece intrínsecamente problemático que sea difícil hacer suposiciones seguras sobre si un momento está congelado o no. ( Object.freeze() tiene un problema similar)

Un momento inmutable no debe ser incongelable, y nunca debe haber ninguna duda sobre si está congelado o no. Esto podría lograrse mediante una variante estricta del patrón del constructor (es decir, el objeto _only_ tiene configuradores hasta que se llame a .build() , después de lo cual _sólo_ tiene getters), o haciendo que el momento se "congele" tan pronto como se instancia, con todos los setters devolviendo un clon.

Por ejemplo:

/* BUILDER PATTERN */
var bldr = moment.immutable()
  .hours(5)
  .minutes(30)
  .seconds(25);

bldr.hours();  // throws exception.  builder has no getters

var time = bldr.build();

time.hours(); // 5
time.hours(6); // throws, OR returns a clone

/*  A more explicit variant:  */
var bldr = moment.immutable()
  .setHours(5);

bldr.getHours; // undefined

var time = bldr.build();
time.getHours(); // 5
time.setHours;   // undefined
/* VALUE OBJECT */
var time = moment.immutable()   // 00:00:00
  .hours(5)       // new object => 05:00:00
  .minutes(30)    // new object => 05:30:00
  .seconds(25);   // new object => 05:30:25

/*  Same thing, but more efficient:  */
var time2 = moment.immutable(5,30,25); // 05:30:25

time.hours();   // 5
time.hours(6);  // new object => 06:30:25

El primer ejemplo es muy parecido a Java, pero también deja poca ambigüedad sobre cómo se construyen los momentos y qué se puede hacer con ellos. También proporciona una ruta eficiente e intuitiva para construir nuevos momentos con poca sobrecarga, y sigue de cerca cómo la mayoría de la gente usa el momento en la actualidad.

Yo estaría a favor de que los establecedores en momentos construidos arrojen excepciones, ya que este comportamiento reduciría aún más la ambigüedad (a expensas de la verbosidad) y obligaría a los desarrolladores a reconocer cada vez que están creando nuevos momentos.

El segundo ejemplo parece que tiene mucha más sobrecarga, porque estamos creando (y descartando) muchos objetos. Pero hay mucho espacio para la optimización. Modern GC es bastante bueno; la evaluación perezosa podría ayudar; podríamos hacer que los objetos Moment sean lo más livianos posible (eliminando el Date subyacente), etc. (para algunas comparaciones, este patrón no es diferente a la forma en que se manejan las cadenas en JavaScript)


Soy fanático de semver, pero el caso de uso del navegador hace que los cambios importantes sean problemáticos, porque será imposible tener dos versiones de moment en la misma página sin un cargador de módulos.

Como se mencionó anteriormente, existe una cantidad de código heredado que depende de Moment. Como mínimo, necesitamos una versión que admita ambos patrones para permitir un período de transición sin problemas.

+1 para métodos componibles que devuelven nuevos momentos. Ni siquiera me importa si son inmutables. Solo dame la composición, para que pueda encadenar métodos o asignar el momento mutado en una línea (en lugar de 2).

@alexyuly, ¿

var a = moment();
var b = a.clone().subtract(1, 'week').startOf('day');

O lo que sea.

@maggiepint Bueno, me siento tonto, parece que podrías componer métodos todo el tiempo. Gracias por el consejo. ¿Quizás hacerlo un poco más claro en los documentos? por ejemplo, http://momentjs.com/docs/#/manipulating/start -of / <- no se menciona ningún valor de retorno.

Pequeña actualización: esta publicación de blog es MI posición sobre este tema en este momento: https://maggiepint.com/2016/06/24/why-moment-js-isnt-immutable-yet/

No hablo por el resto del equipo, pero lo han visto y, en general, diría que todos estamos en un lugar similar.

@maggiepint puntos geniales y muy válidos

Gracias por esto. La inmutabilidad es el rey en redux, así que cambiaré a js-joda con seguridad. Todavía puedo guardar el momento por un tiempo relativo.

Eric Lau - Gmail

El viernes 24 de junio de 2016 a las 11:12 a. M. -0700, "Maggie Pint" [email protected] escribió:

Pequeña actualización: esta publicación de blog es MI posición sobre este tema en este momento: https://maggiepint.com/2016/06/24/why-moment-js-isnt-immutable-yet/

No hablo por el resto del equipo, pero lo han visto y, en general, diría que todos estamos en un lugar similar.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub o silencie el hilo.

Algunos errores / confusión más típicos causados ​​por la mutación: http://stackoverflow.com/questions/26131003/moment-js-start-and-end-of-given-month

+1 para esto, pero en realidad con Redux he descubierto que esto es un problema sorprendentemente pequeño porque no pongo instancias de Moment en el objeto de estado de Redux en absoluto. Solo las cadenas de fecha o marcas de tiempo y yo uso Moment en los métodos de renderizado solo para convertir las cadenas de fecha en otras cadenas.

Hago esto principalmente porque entonces es fácil serializar y deserializar el estado sin ningún trabajo adicional, pero también oculta la mutación muy bien de React y Redux.

Hago todo lo posible para actualizarlo este fin de semana. Tenemos un plan, pero necesito asegurarme de que todo saldrá bien antes de comprometerme con él. Desafortunadamente, me mudaré de Minneapolis a Seattle la próxima semana, por lo que esto puede ralentizarse por un tiempo, pero quiero avanzar.

Pequeña actualización en preparación para una actualización más grande, ya que he notado que esa publicación de blog todavía está recibiendo algo de tráfico. Actualmente estoy reelaborando la compilación del momento para usar Babel. Esto nos prepara para llevar el @butterflyhug al repositorio principal y hacerlo oficialmente compatible. En el proceso, vamos a limpiar algunas cosas sobre el complemento. @butterflyhug amablemente nos ha estado ayudando mucho con esto. Además, me reuniré con John-David Dalton de LoDash (ambos trabajamos en Microsoft) para discutir la estrategia a la hora de incorporar un complemento oficial, como ya lo hizo con LoDash funcional. Próximamente una larga publicación de blog y RFC.

@maggiepint mientras hace que el momento congelado sea compatible oficialmente, ¿planea abordar https://github.com/WhoopInc/frozen-moment/issues/20?

Creo que este enfoque de la inmutabilidad es lo suficientemente bueno siempre que cada llamada a moment() devuelva un momento congelado de forma predeterminada, y los desarrolladores no tienen que recordar llamar a .freeze() cada vez.

@gabrielmaldi Buena pregunta. Estoy escribiendo el RFC (debería estar listo en cualquier momento), y sí, mi objetivo explícito es proporcionar una mejor historia para uso solo inmutable. Mi propuesta está en la línea de mi comentario sobre WhoopInc / frozen-moment # 20, teniendo en cuenta los métodos estáticos. Publicaré un enlace a mi RFC aquí y en ese número cuando abra mi PR contra el repositorio de RFC, y ciertamente agradeceríamos los comentarios de la comunidad sobre la propuesta en ese momento.

Terminé de escribir el borrador del RFC y abrí un PR .

Es un documento bastante largo, en parte porque todavía hay algunas preguntas pendientes sobre cómo queremos ofrecer esta funcionalidad a los usuarios, por lo que estoy tratando de resaltar los pros y los contras de varios enfoques allí. Pero creo que las ideas de implementación son bastante sólidas, por lo que me encantaría saber de la gente de aquí si tiene reservas sobre la API propuesta para el usuario .

Resumen ejecutivo de RFC con nuestras preguntas principales por responder: https://maggiepint.com/2016/07/16/immutability-its-happening/

@maggiepint Traté de publicar un comentario sobre ese artículo, pero por alguna razón lo tragué. Esto es lo que escribí:


Mi mayor preocupación con estos cambios es que responden a una parte desproporcionadamente vocal y expresiva de la comunidad, evitando el silencioso baluarte de los desarrolladores ordinarios que ni siquiera son conscientes de que se está llevando a cabo esta discusión.

Los hilos de GitHub no son un microcosmos de la comunidad de desarrollo en general. Este sitio sufre el mismo sesgo de participación que muchos foros en la web, y está sesgado hacia cierto tipo de desarrollador: intelectualmente comprometido con la teoría de la computación; interesado en ideas más que en aplicaciones; y me atrevo incluso a decir que socialmente se inclina a unirse en torno a las tendencias populares. Estos desarrolladores se sienten naturalmente atraídos por las causas célebres filosóficas como la inmutabilidad y la programación funcional, y tienen un acceso más cercano a usted que cualquier otro grupo. Serán la voz más fuerte de la sala y clamarán por este cambio, pero ¿qué pasa con el resto del mundo?

El mundo en general quiere cosas que funcionen. Quiere saber que la biblioteca que usa actualmente seguirá recibiendo actualizaciones, al menos correcciones de errores, pero idealmente pequeñas mejoras incrementales que mejoren sus vidas. Pero no lo dice, porque no busca activamente estos foros y porque se necesita una piel dura para hablar en contra de la tendencia.

Si tiene la intención de realizar este cambio, creo que tendrá que exponerles a estas personas un caso muy claro de por qué este cambio mejorará sus vidas; por qué deberían actualizarse; por qué no deben preocuparse de que sus proyectos heredados no reciban correcciones de errores indirectos; y, esencialmente, qué cosas podrán hacer ahora que no podrían hacer ahora.

También creo que debería tener mucho cuidado de validar la importancia de este cambio en términos reales. Me pregunto si debería publicar este cambio como un complemento o envoltorio, y supervisar su aceptación cuidadosamente durante varios meses antes de fusionarlo en el tronco. Si la inmutabilidad ha sido sobrerrepresentada como una preocupación de nicho, habrá encontrado una manera de satisfacer a estos usuarios vocales sin cambiar el curso de la biblioteca en su conjunto.

Como usuario por primera vez, terminé aquí después de un tiempo perdido con startOf endOf. ¡Estos métodos están cambiando sorprendentemente!

+1 para inmutabilidad total

Quizás otra solución sea hacer que sea dolorosamente obvio que los objetos en momentjs son mutables . La documentación lo menciona en la sección de clonación, pero NO es lo suficientemente destacado.

Otra solución, si desea mutabilidad, use conceptos orientados a objetos y cree la creación de objetos usando la palabra clave NEW frente al patrón de fábrica moment ().

El mundo en general quiere cosas que funcionen.
... tendrá que explicarles con claridad a estas personas por qué este cambio mejorará sus vidas

Todos los que he presenciado ser nuevos en el momento caen en la trampa de que los "momentos" muten.
Incluso después de 3 años de usar el momento, todavía tengo que decirme a mí mismo "oh, mierda, estás usando .startOf aquí ... mejor revisa dos veces si necesitas una copia".

El comportamiento actual no es intuitivo y hace mucho tiempo que se retrasó.
Intente hacer que array.filter / map mute y vea lo divertido que es.

Con respecto a...
Rendimiento / Memoria: nunca he encadenado más de 2 funciones en un momento y, por lo general, es .set().get()
Pseudo-inmutabilidad: se necesitarán muchas muchas generaciones hasta que el java-pass-by-ref-gen esté disponible.

Me gusta la idea de @AdamHess sobre elegir si estás buscando OOP o inmutabilidad.

Mis dos centavos sobre por qué nos confundimos es esto: valores de retorno. Si moment.add('1', 'days') regresaba indefinido, como lo hacen las funciones mutables en JS, entonces la confusión desaparecería. Devolver el mismo objeto, al menos para mí, implica que tengo una nueva copia. Por supuesto, eso rompería la capacidad de encadenamiento.

Creo que hay una baja probabilidad de que surjan problemas de uso de la memoria para más desarrolladores (excepto en casos de uso especiales). Sin embargo, la mutabilidad de Moment ya me ha mordido. Las fechas deben tratarse como valores como una cadena o un número.

+1 para inmutable por defecto

Este mismo problema existe para PHP, por cierto. ¿Quieres ser como PHP? 😆

En PHP, lo resuelven proporcionando DateTimeImmutable (además del DateTime normal).

Si no cambiamos el comportamiento predeterminado para que sea inmutable, al menos deberíamos considerar una API alternativa de primera clase como imoment / momenti (o lo que sea). Sin embargo, literalmente siempre usaría eso (sobre la API mutable) y espero que cualquier otra biblioteca que use también use la versión / API inmutable.

Yo también voto por la inmutabilidad, estoy dispuesto a ayudar con la implementación si ese es el plan. Ya me encontré con problemas de mutabilidad al hacer sumas y restas, lo que lo hace aún más confuso es que estos métodos devuelven la instancia debido al encadenamiento.

Por cierto, ¿qué hay de la duración de la clonación? ¿Cuál es la mejor manera de hacer eso? No pude encontrar ninguno que no se sintiera hack.

@ngerritsen Creo que la mejor opción disponible es moment.duration(existingDuration) .

Re: implementación, # 3548 sigue siendo un PR activo. Con suerte, no queda mucho trabajo a nivel de código, pero nunca está de más tener más ojos para validar los grandes cambios. También necesitamos trabajar en la documentación, etc. antes de que podamos hacer un cambio de versión principal, que será necesario para lanzar un cambio como este. Si desea ayudar con alguno de los de esta lista, estoy seguro de que se lo agradeceríamos. 😀

Acabo de pasar una hora tratando de identificar un error sutil causado por .startOf () mutando la fecha original ... Gracias por el arduo trabajo, momentjs hizo un gran trabajo mostrando cómo construir una excelente biblioteca de fechas para JS, pero estoy cambiando to date-fns debido a la naturaleza muy sutil de este tipo de errores y porque después de mi introducción a algunos conceptos generales de FP (principalmente gracias a React, Redux y ELM) comencé a apreciar los beneficios generales de la inmutabilidad.

Por lo que vale, lodash ya ha seguido un enfoque más FP con lodash / fp. Sugeriría echar un vistazo a la forma en que se implementó lodash / fp porque envuelven sus funciones existentes en lugar de tener que completar la reescritura de todo. Los chicos de Lodash también están muy preocupados por el rendimiento.

También estoy de acuerdo con @mull , el problema real se debe a la API de encadenamiento para mí, que en mi opinión tiene algunas fallas de diseño importantes no solo en este caso, sino en general (por ejemplo, jQuery). Sería mejor para mí si las fechas de mutación del método regresaran indefinidas (al menos esta es la regla general que aplico al código que escribo)

Mientras moment.frozen espacio de nombres está en los trabajos, me gustaría recomendar --como anterior suggested-- cartel de usar sólo fecha-FNS .

Acabo de arreglar otro error debido a momentos mutables 🎉

Relacionado tangencialmente, sería increíble si 3.0 pudiera pasar a las clases de ES6:

let mom1 = new Moment();
let mom2 = Moment.parse('2019-03-01T14:55');
// etc

Tal movimiento también podría orientar la discusión sobre la inmutabilidad. Yo diría que todos los métodos deberían ser inmutables con una excepción. Un método llamado .set('minute/hour/year/etc', 18) .

Acabo de comenzar a usar Moment y estaba _horrorizado_ de que esta biblioteca no fuera del todo inmutable desde el principio. Estoy usando moment-inmutable hasta que esto se solucione.

El momento

Echa un vistazo a su nuevo proyecto: luxon
Es muy agradable, moderno, inmutable (!) Y debería funcionar mucho mejor que el momento inmutable, que simplemente envuelve todo en llamadas .clone() .

Para aquellos que deseen pasar de momentjs a un enfoque moderno, consulte https://github.com/you-dont-need/You-Dont-Need-Momentjs

¡Muy sorprendido que sea mutable!

¿Qué tan lejos está Luxon de ser un reemplazo? Una de las razones por las que estoy usando Moment.js es la compatibilidad con la zona horaria: es imprescindible para mi proyecto.

@alamothe Esa pregunta se responde claramente en el sitio web: https://moment.github.io/luxon/docs/manual/moment.html

Cerrando esto. Como han señalado otros, use Luxon si desea una API casi inmutable. Gracias.

¿Fue útil esta página
0 / 5 - 0 calificaciones