Moment: rendre le moment presque immuable

Créé le 3 juil. 2014  ·  163Commentaires  ·  Source: moment/moment

Il y a eu beaucoup de discussions à ce sujet. Voici la proposition :

Les méthodes mutables suivantes deviendront immuables dans la version 3.0.0 : utc , local , zone , add , subtract , startOf , endOf , lang , aussi en duration : add , subtract , et lang .

Pour commencer, toutes les méthodes seront dupliquées avec des variantes methodNameMute . Nous avons également besoin de variantes immuables nommées methodNameImmute . À partir de la version 3.0, les anciennes méthodes simples commenceront à utiliser l'option immuable par défaut.

Ce qui est discutable, c'est :

  • lang devrait-il être rendu immuable
  • tous les getters/setters (y compris get / set ) devraient-ils aussi être rendus immuables
  • nommage des versions mutables et immuables des méthodes
  • et bien sûr - devrions-nous faire le changement, ou simplement nous arrêter à l'API immuable

La bonne partie est que nous pouvons créer des versions immuables des méthodes aujourd'hui et décider plus tard de ce qu'il faut faire. Si nous changeons, cela signifierait également que la branche 2.x serait là pendant un certain temps après la sortie de 3.x .

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

Enhancement

Commentaire le plus utile

Mes deux cents, c'est que nous devrions soit opter pour une immutabilité totale, soit pas du tout. Le fait que certaines méthodes soient immuables ( startOf , add ) et d'autres non ( year , get ) est juste déroutant, et les développeurs devront garder une trace de lesquels sont lesquels.

Tous les 163 commentaires

Mes deux cents, c'est que nous devrions soit opter pour une immutabilité totale, soit pas du tout. Le fait que certaines méthodes soient immuables ( startOf , add ) et d'autres non ( year , get ) est juste déroutant, et les développeurs devront garder une trace de lesquels sont lesquels.

Je préférerais également que tout soit immuable par défaut. Les getters ne sont-ils pas déjà immuables ?

Voici les gros problèmes que je vois avec le passage à l'immuabilité.

Pseudo-Immutabilité

En raison de la nature du javascript, nous ne pourrons jamais avoir une véritable immutabilité.

Le mieux que nous puissions faire est de créer une copie, puis de muter et de renvoyer cette copie. Nous pouvons soigneusement envelopper toutes les méthodes publiques pour nous assurer que nous copions et mutons toujours plutôt que de simplement muter, mais cela n'empêche pas quelqu'un de faire m._d = new Date() ou même m._d.setHours(1) .

Je suis d'accord avec @icambron , si on passe à l'immuabilité, ça devrait être un changement complet. Toute méthode susceptible de modifier une propriété à un moment donné créerait à la place une copie de l'instant et apporterait une modification sur la copie à la place.

Superficie API

La chose malheureuse à propos du passage à la pseudo-immutabilité est que de nombreuses nouvelles API doivent être créées si nous voulons toujours prendre en charge la mutabilité.

Avant, passer de la mutation d'un instant au clonage et à la mutation d'un instant était aussi simple que d'ajouter un .clone() au bon endroit. Maintenant, il faudrait créer des interfaces mutables pour tous les setters, ce qui ajoute considérablement à la surface de l'api.

Cela inclut les ~20 méthodes setter, add/subtract, local/utc/zone/tz, startOf/endOf, lang et toutes les autres méthodes utilisées dans les plugins tiers.

Problèmes de mémoire

Étant donné que nous créons maintenant des copies à chaque fois que nous voulons modifier une valeur, l'utilisation de la mémoire augmentera. Bien sûr, les nouveaux moments seront ramassés, mais le coût supplémentaire associé à ce changement est quelque chose à garder à l'esprit.

Nous devrons faire très attention pour nous assurer que nous ne créons pas des tonnes de clones jetables avec des méthodes qui utilisent d'autres setters.

Pour suivre quelles méthodes sont appelées, j'ai utilisé ce petit wrapper de fonction.

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)
}

Maintenant, lors de l'exécution d'une méthode, nous pouvons voir comment d'autres méthodes du prototype sont utilisées. Toutes ces méthodes n'auraient pas besoin de cloner le moment, j'ai donc ajouté des commentaires sur celles qui nécessiteraient le clonage.

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

C'est 21 copies qui sont créées puis immédiatement jetées. Évidemment, nous pourrions optimiser cela en utilisant des méthodes internes qui sont modifiables et n'exposent que les versions immuables, mais cela ajoutera considérablement à la complexité interne en essayant de garder une trace des moments qui ont encore besoin d'être clonés et de ceux qui n'en ont pas besoin.

Problèmes de performances

Cloner un instant est beaucoup plus lent que muter un instant. J'ai rassemblé quelques tests jsperf pour cela.

http://jsperf.com/moment-cloning

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

Je pense que le deuxième test est une bien meilleure représentation des pertes de performances lors du passage à la pseudo-immutabilité. Si nous multiplions ces résultats par les 21 instances de clonage mentionnées ci-dessus, les temps d'exécution sont d'autant plus lents.

Je suis sûr que nous pourrions optimiser le chemin pour le clonage un instant, mais nous aurions besoin de le rendre 50 fois plus rapide afin d'avoir des performances comparables. Je suis presque sûr que c'est impossible.

Sommaire

Le passage à l'immuabilité augmente considérablement la complexité des API internes et externes et pose des problèmes majeurs de performances et de mémoire. Je ne pense pas que ces coûts valent les avantages que l'immuabilité offrirait.

Je pense que les problèmes de performances répertoriés ici ne sont pas pertinents :

De manière générale, un .clone() initial est nécessaire pour garantir l'exactitude avant d'effectuer la mutation.

Nous ne pouvons pas prétendre que clone() n'est pas nécessaire avec l'API actuelle. Le cas principal ici qui est différent consiste à effectuer plusieurs mutations séquentielles. Ce cas est résolu en créant une API de générateur de sorte que toutes les mutations soient effectuées en tant que mutations sur un seul clone.

Est-ce que je manque d'autres cas d'utilisation courants ?

Mon problème d'origine concernait les méthodes startOf et endOf particulier. Pour une raison quelconque, ces noms pour moi étaient comme « faites-moi commencer un mois » et non « définissez ce moment au début d'un mois ». Des méthodes comme add et subtract sont parfaitement correctes au sens sémantique. Il est tout à fait possible d'ajouter quelque chose à un objet sans en créer un nouveau.
Pour moi personnellement, renommer les méthodes startOf et endOf en quelque chose comme toStartOf et toEndOf (comme "déplacer ce moment au début d'un mois") résoudrait le problème problème. A mon humble avis

@gregwebs Désolé, je voulais dire set ci-dessus.

Je ne suis pas d'accord avec @soswow ; Je pense qu'il doit être cohérent. En fait, je pense que toStartOf implique l'immuabilité encore plus fortement, comme si cela fournissait une présentation alternative à la toISOString . Plus important encore, je pense que nous devons être capables de faire des déclarations telles que "Les setters de Moment mutent des moments" ou "Les setters de Moments renvoient des copies", pas "Eh bien, pour ces méthodes..."

Sur les préoccupations de @timrwood :

Que les objets JS ne soient pas vraiment immuables ne me dérange pas. Le fait est que l'API fournit un contrat immuable. Bien sûr, l'utilisateur peut tricher en jouant avec les propriétés soulignées, et la triche est généralement possible même dans les langues où l'immuabilité est la principale façon de faire les choses.

Sur la surface et à propos des performances : je pense que nous devrons utiliser les mutateurs en interne pour éviter d'utiliser tout ce processeur et cette mémoire [1], nous devrons donc les prendre en charge à un certain niveau. Ensuite, nous pourrions aussi bien les exposer à l'extérieur, comme setYear() , etc. Cela ajoute beaucoup de surface, mais cela n'ajoute pas vraiment beaucoup de complexité ; pour les mutateurs non explicites, cloner en externe, muter en interne.

Une façon de voir cela est que l'utilisateur doit cloner dans son code, donc Moment pourrait aussi bien le faire pour lui. Cela présente un problème avec le chaînage dans des endroits sensibles aux performances, qui pourrait être combattu par une interface de constructeur (selon l'idée de Greg) ou en laissant l'utilisateur utiliser simplement des mutateurs là-bas. Le constructeur ajoute un tas de complexité [2], donc je pense que je privilégie simplement les alternatives de mutateurs explicites. Je pense que la réalité est que la plupart du temps, Moment n'est pas utilisé dans des situations sensibles aux performances, donc ces situations n'ont pas besoin d'être les plus pratiques en termes d'API. Je préfère avoir une belle API immuable avec une trappe de perf pour quand j'en ai besoin.

[1] Les enfants cool de FP Land résolvent ce problème avec le _partage structurel_, mais ce n'est probablement pas pratique ici.

[2] Traditionnellement, les gens font des constructeurs qui sont des objets séparés, mais ce serait vraiment verbeux ici, car il faudrait copier l'ensemble de l'API du setter. Juste spitball, mais une alternative est que .chain() crée un moment de clonage qui a juste un drapeau isBuilding défini dessus. Ensuite, les clones internes sont ignorés, renvoyant simplement l'objet pour mutation. Ensuite, build() désactive le drapeau et renvoie ce clone. Le problème est que vous avez besoin de vos getters pour crier un meurtre sanglant si le drapeau est défini, ou les gens finiront par utiliser les Moments enchaînés mais non construits qui sont soudainement mutator. Ensuite, vous devez différencier les getters appelés en externe et en interne. Blech. Une autre alternative consiste à décomposer en interne la fonctionnalité requise par le générateur dans un mixin et à l'utiliser à la fois dans le générateur et dans Moment, mais ce n'est probablement pas réalisable du point de vue de l'organisation du code.

ce qui a fonctionné pour moi, c'était d'ajouter un paramètre supplémentaire aux fonctions, un indicateur (je m'appelais self) pour indiquer la mutabilité, par défaut est inmutable (renvoyer une copie ou un nouvel objet), et quand je détecte des performances, je mets l'indicateur sur true

ce point de vue a résolu beaucoup de conflits,
ayant des fonctions avec un nom similaire exécutant presque le même code,
ou devoir changer le nom de la fonction et probablement les paramètres lorsque je détecte des points de performance
dans mes méthodes publiques, je démarre le code appelant les fonctions avec une copie et les appels suivants avec le drapeau à true
avec cela, je peux aussi enchaîner les fonctions

dans mon code, je travaille avec des tableaux de tableaux (comme une table, un tableau de lignes)
j'ai donc des fonctions à filtrer, à union, etc. le tableau initial et les appels suivants, je travaille avec la même ligne de suppression de tableau dont je n'ai pas besoin

un exemple basique qui pourrait être ici :
moment.add = function(mesure, montant, soi){
}

moment.add = fonction (mesure, montant, soi) {
var $moment = soi ? this : this.clone();
// le vrai code
retourner $moment ;
}

Merci à tous pour leurs 2 centimes :)

Pour le protocole, je suis d'accord sur le dernier post de @icambron sur tous les points.

Il reste deux grandes questions.

Le plus simple est ce que devrait être la nouvelle API, deux options :
1.1 méthodes nommées différemment (mutables et immuables) year / setYear , startOf / setStartOf
1.2 ou builder api chain().mutators().build() , qui est la version non hacky de ce que @lfnavess proposait.

L'API du constructeur a définitivement l'air plus sexy, mais il faut veiller à ce que les objets ne restent pas en mode construction trop longtemps, ce qui ajoute une autre source de problèmes pour nous et les utilisateurs.

Maintenant, le problème est la migration vers la nouvelle version. Je vois deux options ici :
Les développeurs 2.1 doivent réécrire leur code (les regex folles peuvent fonctionner dans les solutions 1.1 et AST pour 1.2 - étant donné que personne n'utilise year et month comme noms de leurs propres méthodes). python a adopté cette approche -- nous pouvons tous voir le résultat -- un tout nouveau langage est né !
2.2 option pour activer toujours l'API du constructeur (comme maintenant) et un moyen de la désactiver pour le nouveau code. Cela semble plus _évolutif_, mais la confusion que cela causerait n'en vaut probablement pas la peine. Chaque instant a maintenant deux drapeaux : est-il mutable, et dans le cas où c'est le cas, est-il strictement mutable (pas de getters) ou transitoirement mutable (getters ok). Sans parler de la réception d'objets momentanés dans les fonctions -- vous devriez vérifier quel est le mode, assurez-vous de le maintenir... quel gâchis !


Et maintenant une idée folle qui m'est venue maintenant

Clonage de copie sur écriture

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

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

Je ne sais pas combien peut être rasé avec cette approche, étant donné que les instances sont assez légères. De plus, tous les mutateurs doivent maintenant effectuer un contrôle.

Il existe plusieurs façons de mettre en œuvre avec des performances variables dans différents scénarios. La bonne nouvelle est qu'il est rétrocompatible et nous économiserons à nous et à nos utilisateurs beaucoup d'efforts. Et je pense que c'est plus important que de réinventer la roue.

Je ne sais pas ce que nous gagnons ici.

Le passage à l'immuabilité a une tonne de coûts associés et peut-être que ça me manque, mais
Je ne vois pas vraiment d'avantages comparables.

Les principaux avantages semblent être la préférence des développeurs. Est-ce tout pour que les développeurs n'aient pas
penser à s'approprier un moment en le faisant circuler ?

Je ne pense pas que le passage à l'immuabilité rendra les bugs moins fréquents, cela ne fera que
changer le type de bogues. L'exemple de @ichernev montre même le type exact de bogues qui
surface, qui sont tout aussi difficiles à repérer.

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);
}

Voici une liste des avantages/inconvénients entre la mutabilité et l'immutabilité. Si j'ai raté quelque chose,
faites le moi savoir et j'éditerai ce commentaire.

| Immuable | Mutable |
| --- | --- |
| Certains développeurs le préfèrent | Certains autres développeurs le préfèrent |
| Évite les bugs lors du passage des moments | Évite les bugs en oubliant d'attribuer des moments clonés |
| Avec quelques dizaines de nouvelles méthodes d'API, la mutabilité sera également prise en charge | Avec la méthode .clone() existante, l'immuabilité est déjà prise en charge |
| | Un ordre de grandeur plus rapide |
| | Utilise beaucoup moins de mémoire |

Je pense que l'immutabilité est utile, mais je ne pense pas que ce soit un bon ajustement dans JavaScript. Je pense qu'une interface immuable peut avoir du sens pour un langage comme Elm, où l'immuabilité est attendue, mais pour JavaScript, je pense que la mutabilité est attendue.

Une grande partie des API pour les typeof a === "object" intégrés sont mutables. Array#push,pop,reverse,sort,shift,splice,unshift modifient tous le contenu d'un tableau plutôt que de renvoyer un nouveau tableau. Les 16 méthodes Date#setX modifient leur instance.

Je pense que nous voyons beaucoup de gens se plaindre du fait que des moments sont mutables, mais si nous changeons, je pense que nous aurons autant de personnes à se plaindre. Cela s'est déjà produit avec les méthodes eod/sod il y a deux ans.

Après avoir examiné un tas de vieux problèmes sur la mutabilité, je suppose que je sonne probablement comme un disque rayé ici. De part et d'autre, ce sont les mêmes points qui sont soulevés depuis quelques années. Je voulais juste m'assurer qu'un argument en faveur du maintien d'une API mutable était représenté dans la discussion.

@timrwood ce sont de bonnes comparaisons, mais il est assez clair que vous n'avez pas pris le temps de comprendre le cas d'utilisation immuable. Nous avons déjà expliqué pourquoi les comparaisons de performances que vous avez publiées supposent une API mal implémentée et n'ont pas de sens.

La comparaison de bogues est également invalide. Étant donné que momentjs prend en charge une API de chaînage, on pourrait s'attendre à ce qu'elle soit immuable.

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

Donc, immuable et mutable ont le même problème en ce moment. Vous pourriez l'éviter avec la version mutable actuelle si vous vous débarrassiez de l'API de chaînage.

L'API immuable est donc préférable à mutable car vous pouvez passer un moment en toute sécurité entre les fonctions. Avec les moments mutables actuels si je passe un moment entre fonction j'ai 2 options

1) La méthode insensée du buggy (c'est probablement la plus courante) : étudiez tout le code source pour vous assurer qu'il n'y a pas de mutations indésirables. Écrivez des tests unitaires pour vous assurer que des mutations indésirables ne s'infiltrent pas.
2) La manière saine (laissons plutôt supposer que tout le monde fait cela), programmation défensive : n'oubliez pas d'appeler la fonction clone() avant de muter dans ma fonction.

Avec l'API immuable, nous n'avons pas à nous rappeler d'appeler clone() à chaque fois. Au lieu de cela, nous devons nous rappeler d'appeler la fonction API qui nous permet d'éviter le clonage, mais ce n'est qu'une optimisation des performances, pas un problème d'exactitude.

il est assez clair que vous n'avez pas pris le temps de comprendre le cas d'utilisation immuable

C'est une déclaration injuste. Mon argument est que je vois les avantages, mais ne pense pas qu'ils l'emportent sur les coûts.

vous pouvez passer un moment en toute sécurité entre les fonctions

nous n'avons pas à nous souvenir d'appeler clone

N'est-ce pas le cas d'utilisation de l'immuabilité ? S'il y a autre chose que je n'ai pas pris le temps de comprendre, faites-le moi savoir, mais cela semble être le seul argument depuis quelques années.

@timrwood oui, c'est tout le cas.

Mais je ne vois aucun signe de votre part reconnaissant que votre cas _contre_ l'immuabilité (performances horribles, favorise un type de bogue différent non présent dans l'API mutable) n'est pas valide.

je pense que nous devrions nous en tenir au point de vue ecmascript 5, et peut-être ajouter une fonction qui gèle profondément l'objet actuel, ou un indicateur global qui crée automatiquement des objets gelés

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

peut-être un paramètre supplémentaire dans le constructeur pour créer un objet de gel, car un objet de gel ne peut pas être dégelé

@lfnavess J'ai pensé à freeze avant de mentionner la copie en écriture. Le problème est que ... personne ne l'utilise / n'en sait rien, et cela n'aide pas non plus lorsqu'il ne lève pas d'exception (en mode non strict) - cela crée en fait des bogues fous à suivre.

@timrwood Je ne pense pas avoir été clair dans mon exemple. Sur la ligne m.year(2014) // clone here je voulais dire qu'en interne, moment ferait en fait un clone (allouerait plus de mémoire) et m pointerait vers cette nouvelle mémoire, automatiquement. Eh bien, cela signifie essentiellement que clone() devrait également allouer un peu de mémoire shell (quelque chose pour pointer vers la représentation de la date interne), je ne suis tout simplement pas sûr de ce que l'on gagnerait en le faisant.

Création d'une version à moitié assaisonnée de clone , qui clone uniquement l'interface, et la possibilité de modifier les données sous-jacentes (du stockage partagé au stockage spécifique à l'instance) - cela dépend vraiment du coût des objets Date. L'inconvénient est que chaque fonction doit faire this._storage._d au lieu de this._d , et je ne sais pas si cela surmonterait l'avantage.

Je n'ai reçu aucun commentaire sur la manière de gérer la migration des bibliothèques/utilisateurs existants du moment. Je n'aime vraiment aucune des options que j'ai énumérées ci-dessus.

La compatibilité inverse est, selon l'OMI, l'argument le plus solide contre cela. Si nous faisons cela, nous devons simplement accepter que c'est un grand changement décisif. Si nous ne voulons pas accepter cela, nous ne devrions pas le faire.

Il convient de mentionner à re:perf qu'il y a aussi d'énormes avantages que vous pouvez tirer de l'immutabilité ; ce n'est pas un hit perf monotone. Par exemple, vous pouvez mettre en cache des éléments au niveau de l'objet, car ils ne changeront jamais. Je pense aussi que nous devrions être capables d'optimiser la merde vivante avec clone() ; AFAIK, cela implique de cloner une date et de copier comme cinq valeurs ; Je pense que nous devrions simplement les coder en dur comme newThing._offset = oldThing._offset .

Edit, arg, no - les plugins ajoutent aussi des champs (par exemple ici ).

étant donné le fort désir de compatibilité descendante tout en gardant les choses légères, je pense que la meilleure solution est de bifurquer les sources javascript (soit dans les sources de ce projet, soit de démarrer un tout nouveau projet). Il y a de la place pour plus d'une bibliothèque de temps pour Internet.

Aussi: re: l'idée de @ichernev sur le partage structurel, une possibilité est d'utiliser l'héritage de prototype au lieu d'envelopper un objet d'état partagé.

Chez WhoopInc, nous sommes cachés dans cette discussion depuis un certain temps. Étant donné que la discussion ici semble tourner en rond, j'ai pris un peu de temps ce week-end pour explorer à quoi pourrait ressembler une version immuable du moment avec une API de constructeur. (Je n'ai pas l'intention de soumettre un PR contre le moment à moins d'y être invité, car j'apporte délibérément des modifications d'API plus strictes que je ne m'attendrais à voir implémenté dans le moment lui-même.) Voici le résultat : https://github. com/WhoopInc/moment-gelé

Je ne suis que depuis quelques heures, donc tout est vraiment approximatif, mais sur la base des résultats des tests, je pense que la plupart des fonctionnalités de base du moment fonctionnent. Je continuerai à suivre cette conversation, et j'apprécierais les commentaires spécifiques à notre fork dans les problèmes de notre repo.

Je vais essayer de publier des documents mis à jour sur ce référentiel ce soir, mais en gros, je viens de diviser toutes les méthodes de définition et de mutation dans un objet de génération distinct. Ainsi, l'utilisation de l'API peut ressembler à frozenMoment("2014-07-21").thaw().subtract(1, "day").startOf("day").freeze().format("YYYY-MM-DD") . (Bien que dans cet exemple particulier, il serait plus efficace de simplement démarrer la chaîne avec un générateur au lieu d'initialiser un générateur à partir d'un FreeMoment, en utilisant frozenMoment.build("2014-07-21").subtract... )

FWIW, lorsque j'ai commencé à utiliser moment, j'avais supposé qu'il suivait les principes de FP et renverrait la même valeur à chaque fois que j'appelais une fonction :

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

Bien sûr, je n'ai pas obtenu les résultats que j'espérais. Cela m'a pris au dépourvu en tant que nouvel utilisateur.

Considérez ce pseudocode, qui montre comment je m'attendais à ce que le code se comporte :

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

Mais au lieu de cela, cela a fini par fonctionner comme ceci, ce qui me semble étrange :

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

Pour l'instant, même si c'est assez fastidieux, je me contente soigneusement de .clone() partout.

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

OMI, Javascript est sujet à des erreurs subtiles et je pense que les principes de FP aident à minimiser ces erreurs.

Je comprends que ce soit une décision difficile à prendre. J'apprécie votre travail. Moment.js est incroyable.

+1 pour 100% d'immuabilité.

C'est vraiment frustrant de ne pas être immuable.

+1 pour 100% d'immuabilité en version 3

Il devrait certainement y avoir une API immuable. En tant qu'utilisateur d'autres bibliothèques de dates (notamment .NET DateTime et Joda Time / Noda Time), je m'attends intuitivement à ce que la méthode add ne mute

+1 pour l'immuabilité

+1 pour 100% d'immuabilité

Si la décision est prise pour l'immuabilité, je serais prêt à donner de mon temps pour y arriver. Peut-être un jumelage via un appel vidéo. J'aimerais contribuer davantage à l'open source mais j'ai besoin d'apprendre les ficelles du métier.

Pour moi, l'immuabilité est préférable, mais cela aurait dû être fait dès le départ. Il s'agit d'un changement radical. Un fork de ce projet qui se concentre sur l'immuabilité serait une meilleure idée.

@dsherret C'est à cela que sert semver . Nous aurions juste cogné la version majeure.

Cependant, avec quelques efforts, il pourrait être introduit comme option de configuration : "Voulez-vous que tout soit immuable ? Vrai ou faux". La valeur par défaut serait false.

Plugin de moment immuable non officiel ymmv non pris en charge ici : https://gist.github.com/timrwood/fcd0925bb779f4374a7c

Haha ! J'ai été surpris de venir ici bien plus tard et de découvrir que j'étais l'un des premiers partisans d'une API plus immuable.. :)

Et oui je suis +1 pour l'immuabilité pour la prochaine version majeure.

Un autre +1 pour le moment immuable par défaut de ma part.
Et voici ma concoction « instant » : https://gist.github.com/idrm/a91dc7a4cfb381dca24e (à utiliser à vos risques et périls !). Remplacez simplement vos appels moment() par imoment() et cela devrait suffire. Tous les appels de fonction statique moment.xyz() (par exemple moment.min(), moment.max(), etc.) doivent rester tels quels.

+1million de dollars

+1 pour l'immuabilité

Puis-je également ajouter un +1 à une suggestion précédente de ce fil de discussion pour renommer certaines des fonctions afin qu'elles soient plus faciles à lire ("startOf" à "toStartOf", "add" à "plus", "month" à "withMonth ", etc.)? Autrement dit, en supposant que vous empruntiez la route immuable par défaut. J'utilise beaucoup Joda Time, et c'est un jeu d'enfant de comprendre ce que signifie, par exemple, "date.withDayOfMonth(1).withDayOfWeek(DateTimeConstants.MONDAY)".
Ceux-ci ne doivent pas non plus être dans la distribution principale JS; un module complémentaire qui les place au-dessus du JS vanille fonctionnerait tout aussi bien (bon sang, j'envisage fortement d'écrire moi-même un module complémentaire aligné sur le temps de Joda à combiner avec mon mod "instant").

@ichernev , @icambron , avez-vous pris une décision à ce sujet ? Les moments seront-ils immuables en 3.0 ? Si oui : quand pensez-vous que la 3.0 sortira ? Je demande parce que j'envisage d'utiliser le moment figé ou d'écrire moi-même un petit emballage - et je me demande si je devrais attendre.

Pour votre information, le moment gelé a principalement été dans un modèle d'attente récemment - j'ai porté un tas de PRs de Moment en amont, mais je n'ai pas vraiment travaillé sur l'un des autres refactorings qui devraient idéalement se produire dans cette fourchette.

Cela dit, le moment gelé devrait très bien fonctionner si vous n'avez besoin que des paramètres régionaux anglais par défaut. (Tout fonctionne pour mes cas d'utilisation et j'ai maintenu la couverture de test unitaire élevée de Moment.) Les paramètres régionaux non anglais sont cassés car je ne les ai pas mis à jour après le portage des API de paramètres régionaux récemment refactorisées de Moment.

Une fois que nous aurons pris une décision pour Moment 3.0, je prévois de travailler un peu plus sérieusement sur le travail d'immuabilité dans Moment, ou sur le fork du moment figé, selon le cas. Mon objectif initial serait de corriger la prise en charge des paramètres régionaux et de maintenir la parité des fonctionnalités avec l'API de Moment 3.0.

+1 pour l'immuabilité

+1 pour l'immuabilité. Qu'en est-il de la méthode format qui fait également muter l'objet ?

+1 pour un instant immuable.js
Ou peut-être un fork de moment.js ? instant-immuable.js ? Puisque ce sera certainement un changement décisif.

:100:
faire les imootables !

+1 de nos jours, l'immuabilité est quelque chose que j'attends de toute bonne API JS

:+1: Oui s'il vous plaît, nous aimerions beaucoup cela. Actuellement, nous saupoudrons .clone() partout.

+1 ce serait une très belle amélioration

:+1: immuable toutes choses

+1 pour immuable

Rendez tout immuable. J'en ai marre de cloner chaque instant (maintenant) variable avant d'opérer sur maintenant variable, puis maintenant est à nouveau modifié.

+1 pour l'immuabilité

Je ne me serais pas attendu startOf('day') ce que

Je suis tout à fait d'accord pour dire que la plupart des opérateurs de moment.js sont maladroits dans leur mutabilité. mmnt.startOf('day') est super contre-intuitif en ce sens qu'il mute mmnt .

J'utilise moment.js pour les cas d'utilisation de type calendrier avec beaucoup de boucles et de comparaisons de dates. J'ai rencontré les problèmes de performances avec clone() et ils sont atroces. Avoir un certain contrôle sur ce qui clone et ce qui mute est essentiel pour moi et probablement pour d'autres.
Même si avoir clone() partout semble gênant au début, ce qu'il fait est limpide et rend la refactorisation pour les performances super facile pour moi.

Si chaque méthode commence à utiliser aveuglément clone() interne pour avoir une API plus agréable, je pense que nous aurons raté le point.

mon 2¢ :-)

@jdurand Je préfère muter explicitement que cloner explicitement.

@dsherret Cela ne me dérange pas explicitement. Ma principale préoccupation est de ne pas cloner implicitement car c'est une opération très coûteuse.
Quelqu'un a mentionné que les setters devraient retourner une copie clonée et cela m'a fait peur; Ce serait très inefficace.

@jdurand cela pourrait être plus inefficace, mais je pense qu'un clone implicite profiterait à la majorité des applications où la différence entre les objets clonés et mutés ne ferait aucune différence notable pour l'expérience de l'utilisateur final. Je pense que la facilité du développeur et essayer d'éviter les erreurs du développeur devraient avoir la priorité sur quelques millisecondes enregistrées, car la majorité des développeurs n'effectuent pas des milliers d'opérations de date à la fois. Pour ceux qui le sont, ils pourraient peut-être dire explicitement qu'ils veulent muter au lieu de cloner.

Sidenote: avec ce changement , je pense que des améliorations de performance pourraient être si ... par exemple, le clonage pourrait être éliminé en faisant référence à la place le passé objet immuable et stocker l'opération à faire pour cet objet (ex. add(1, 'days') ). Le résultat ne serait alors calculé qu'en exécutant les opérations lorsque quelque chose comme .toString() , .format() , .toDate() , .day() , etc... est appelé. Ce serait un changement radical et cela pourrait ne pas être plus rapide ... certains tests unitaires devraient être effectués pour comparer les performances (de plus, il pourrait y avoir d'autres problèmes que je n'ai pas pris en compte car je n'ai jamais regardé de code dans moment.js autre que la façon dont il clone).

@dsherret J'aime l'approche _builder_/_lazy_ ; avec le recul, il aurait probablement dû être construit comme ça dès le départ.
Comme vous l'avez dit, je pense qu'un fork immuable avec la compatibilité API à l'esprit serait le meilleur.

2 centimes de plus :

  1. Faut-il vraiment s'inquiéter de la performance, alors que le moment est clairement construit pour la commodité plutôt que pour la performance ? Je pense que l'analyse de 'year' dans m.add('year',1) est beaucoup plus lente que le clonage.
  2. À moins qu'il n'y ait un fork total (nom différent, doc différent), il sera difficile de maintenir 2 versions. Je pense que quelqu'un d'intelligent devrait avoir une idée pour générer moment.immutable.min.js et moment.min.js à partir de la même base de code...

Depuis quand avons-nous si peur de casser les changements ? La version actuelle est stable et les gens peuvent toujours l'utiliser sans refactoriser leur base de code.

Maintenir deux bases de code est pénible, vous ralentit et ne vaut pas vraiment la peine d'avoir une version mutable/immuable.

Alors allons-y avec un moment totalement immuable, bousculons la version majeure et finissons-en :dancers:

J'ai trouvé ce fil alors que je venais de commencer à utiliser cette bibliothèque, mais je me suis arraché les cheveux en déboguant du code et en faisant face à ce qui me semble être des effets secondaires imprévisibles d'être mutables. J'adorerais voir une version entièrement immuable de la bibliothèque !

Plug sans vergogne : j'en ai marre d'attendre une décision ferme ici. Au cours des derniers jours, j'ai ressuscité Frozen Moment et l'ai réécrit pour qu'il serve de plugin pour Moment lui-même. Chapeau à @wyantb pour m'avoir aidé à faire la première version

Frozen Moment fournit un type immuable qui fonctionne exactement comme Moment. Fondamentalement, la version immuable enveloppe les fonctionnalités de Moment et appelle .clone() pour vous chaque fois que cela est approprié.

Pour ceux qui aiment les API de construction, je vous mets au défi de considérer Moment lui-même comme une très belle implémentation d'un objet de construction ! Frozen Moment ajoute le type immuable de base que nous voulons tous, et un mécanisme pour construire un Frozen Moment immuable à partir d'un Moment mutable.

Pour ceux qui veulent juste travailler avec une API immuable pratique -- eh bien, j'ai l'intention de prendre en charge cela aussi. Je n'ai pas encore construit de constructeur qui construira directement une instance Frozen, mais c'est sur la liste TODO . À court terme, la solution de contournement consiste à tout créer avec moment().freeze() ou moment.utc().freeze() .

Frozen Moment est évidemment une jeune base de code, il y a donc probablement quelques aspérités – mais j'encourage quiconque ici à l'essayer et à signaler les problèmes pour tout ce qui ne fonctionne pas comme prévu.

Oh, encore une chose : je ne fais pas encore de publicité pour cela, mais les instances de Frozen Moment devraient "juste fonctionner" avec la plupart des plugins Moment. Assurez-vous simplement que tous vos autres plugins Moment s'enregistrent avant Frozen Moment. Si vous trouvez un plugin qui ne fonctionne pas comme prévu avec des Frozen Moments immuables, signalez un bogue et je l'examinerai.

+1 sur l'immuabilité

+1 pour immuable

Quelqu'un a-t-il envisagé d'implémenter Moment au-dessus d' Immutable JS ? C'est une bibliothèque optimisée pour l'immuabilité dans JS, elle réutilise les parties inchangées d'un objet immuable, réduisant ainsi les problèmes de mémoire.

+1
Je viens de corriger un bug vieux de 3 ans à cause de ça : https://github.com/Saleslogix/argos-saleslogix/commit/87b35b22c1a42670da369701b15e2bdb3786cabc

Alors les utilisateurs demandent l'immuabilité mais l'équipe de base trouve des excuses pour ne pas le faire ? :p
Allez les gars, ce changement est bien plus important que de réécrire le code dans ES6 ^^ Dans sa forme actuelle, l'API est tout simplement mauvaise, un peu comme celle de JS Array où certaines méthodes sont immuables (filtre, concat, etc) mais certaines d'autres ne le sont pas (reverse, sort) sauf que leur contrainte de rétrocompatibilité est infiniment plus élevée que pour une bibliothèque.

+1

un petit piège qui m'attrape toujours (et à mon humble avis c'est une bonne raison pour l'immuabilité):

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

cela ne génère malheureusement pas de tableau avec les noms des jours mais quelque chose d'étrange car vous calculez en fait la date comme ceci :

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

donc vous devez le refactoriser dans ceci:

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 excellent exemple

+1 pour l'immuabilité

+1

@faebser m'est arrivé ce matin. La liaison bidirectionnelle + la mutabilité d'Angular rend difficile la conservation des dates de clonage pour éviter de modifier les dates actuelles.

+1 pour l'immuabilité, cela ne m'a coûté que quelques heures.

:+1:

+1 pour l'immuabilité

Je suis un peu déchiré par ce sujet.

Le puriste en moi veut crier "+1 pour l'immuabilité ! Les objets Moment sont clairement du genre ValueObject ."

Cependant, nous ne pouvons pas ignorer ce moment.js est le 13e référentiel javascript le plus populaire sur GitHub (et le 24e au total), et cette recherche de "moment" sur bower.io renvoie 111 résultats correspondants. Même si nous pouvons fournir aux constructeurs d'applications un moyen progressif d'implémenter une version immuable de moment, cela va causer un énorme désordre parmi ses dépendances.

@ichernev Peut-être une suggestion plus humble : serait-il possible de consacrer une petite partie de la page de documentation de Moment à parler de la mutabilité par rapport à l'immutabilité ? Vous pouvez énoncer brièvement votre position officielle sur le sujet, et peut-être ajouter un bref résumé des arguments, placer un lien vers ce fil, ou si vous souhaitez une contribution spécifique à la discussion, cela pourrait fonctionner comme un CTA.

Pour le moment, la page de documentation ne mentionne pas le terme "immuable". Googler "moment immuable" vous amène à cette page, mais cela m'a pris deux heures de lecture et je ne suis toujours pas sûr de votre position actuelle sur le sujet. Ce serait formidable si le meilleur hit de Google pour "moment immuable" donnait une réponse rapide sur l'avenir de l'immutabilité dans le moment :)

Pour citer @jehoshua02 :
"Je comprends que ce soit une décision difficile à prendre. J'apprécie votre travail. Moment.js est incroyable."

Voici ma proposition. Au lieu de rendre le moment de base immuable, ajoutez une usine moment.immutable . Ce serait une propriété de la fonction moment et inclurait la même signature API exacte que moment , mais immuable.

Il pourrait même s'agir simplement d'une extension de prototype de l'usine mutable moment , utilisant les fonctions de ce prototype, mais en clonant à la place.

EDIT : Il semble que WhoopInc/frozen-moment soit exactement ce que je recherche.

Les changements de rupture de raison d' être des principaux numéros de version. Toute personne utilisant Bower et npm aura la possibilité de s'en tenir au numéro de version majeur actuel ; nous ne devrions pas nous soucier de la compatibilité descendante ici - sauf peut-être pour les personnes qui ne font que servir cela à partir de CDN. Mais s'ils utilisent momentjs de CDN, ils ne sont probablement pas du tout intéressés par la mise à jour de la bibliothèque de temps en temps.

Je dirais qu'avoir l'immuabilité dans la prochaine version majeure - ou la version majeure après cela - devrait être sur la feuille de route.

Il semble donc que je viens de rencontrer ce problème également.

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

Je suis donc tout à fait pour l'immutabilité à tous les niveaux.

+1 pour l'immuabilité

Je viens de perdre une soirée à cause de ce comportement surprenant et inattendu.
Un autre +1 pour l'immuabilité avec un changement de version majeur correspondant pour que ce soit clair.

+1 pour l'immuabilité

+1 pour une immutabilité totale.
La quantité collective d'heures perdues en raison de "parfois muables, parfois immuables" doit être assez importante.

Ouais je veux dire sérieusement. Qui se soucie des performances dans une bibliothèque datetime ? Comme vraiment? Je suppose que 99,9% des utilisateurs ne font rien qui nécessite de bonnes performances, même à distance. En règle générale, vous gérez quelques rendez-vous, ou dans le pire des cas, quelques centaines. Les quelques utilisateurs qui gèrent des millions de dates par seconde peuvent utiliser des points d'API mutables optimisés.

L'immuabilité est le seul choix de conception sain. Il existe plusieurs études qui montrent que la programmation avec des types immuables est beaucoup moins sujette aux bugs qu'avec des types mutables.

+1 pour l'immuabilité. Cela m'a coûté quelques heures.

Une partie du problème est que les noms de méthode comme .startOf() n'impliquent pas de mutation de l'objet sous-jacent.

J'ai rencontré des problèmes de performances avec Moment, je peux donc vous assurer que cela peut parfois arriver.

Cependant, je ne suis pas convaincu que les moments immuables seraient intrinsèquement moins efficaces, et je peux envisager quelques cas où ils seraient plus efficaces.

Ce débat a été réglé il y a longtemps dans le monde Java. Des dates immuables ont été gagnées et l'implémentation la plus populaire (JodaTime) est finalement devenue une partie de la bibliothèque standard de Java 8.

Travailler avec les LocalTime Java 8 a été l'un de ces « Pourquoi n'avons-nous pas _toujours_ fait ça ? » des moments. J'évangélise rarement les technologies, mais honnêtement, je ne vois aucun avantage aux objets de date mutables.

Alors, oui... Je déteste que ces fils de discussion soient inondés de +1, mais la vérité est que quelqu'un d'autre va créer une bibliothèque de dates JS immuable si Moment ne le fait pas.

Je suis récemment tombé sur un nouveau module npm qui prétend porter une grande partie de l'API JodaTime (c'est-à-dire les dates Java 8) vers JS.

Cela apporterait des éléments tels que l'immutabilité, LocalDate et LocalTime au nœud et au navigateur.

Après avoir travaillé avec ces concepts en Java, tout le reste semble fastidieux et sujet aux bugs.

Relier?

Le ven 11 décembre 2015, 16h30 Andrew Schmadel [email protected]
a écrit:

Je suis récemment tombé sur un nouveau module npm qui prétend porter une grande partie de
l'API JodaTime (c'est-à-dire les dates Java 8) vers JS.

Cela apporterait des choses comme l'immuabilité, LocalDate et LocalTime à
nœud et le navigateur.

Après avoir travaillé avec ces concepts en Java, tout le reste semble kludge-y
et sujettes aux bugs.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/moment/moment/issues/1754#issuecomment -163964349.

Wout.
(tapé sur mobile, excusez le laconisme)

Comme je ne suis pas encore intervenu, je vais simplement déclarer que je suis en faveur de l'immuabilité au moment 3.0. Principalement parce que je viens de l'école de pensée DDD, où des objets comme moment seraient considérés comme des _objets de valeur_, et sont donc mieux implémentés comme immuables.

Même s'il y a un impact significatif sur les performances, c'est toujours la bonne chose à faire. Le moment devrait s'intégrer naturellement dans les conceptions des autres. L'API intuitive l'emporte sur les performances, et la mutation n'est pas intuitive sur les objets de valeur (IMHO).

Je pense également que le moment 3.0 devrait supprimer sa dépendance à l'objet Date , mais c'est une discussion pour un fil différent.

Je suis tout à fait d'accord avec @ mj1856 ici.

J'ai utilisé Object.freeze sur des instances de moment et cela a généralement atteint ce dont j'avais besoin; sauf que je viens de découvrir que ce qui suit échoue:

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

L'éxéption:

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)

Cela peut-il être corrigé afin que Object.freeze puisse être utilisé quand vous le souhaitez ?

@wmertens Je suppose que c'est ça: https://github.com/pithu/js-joda

@ichernev , @ mj1856 , comme je n'ai pas été impliqué dans le développement de base de moment depuis un certain temps et que l'immuabilité a un intérêt assez important, je retire ma position précédente.

Je ne sais pas si j'étais le seul bloqueur à ce sujet, mais je suis à l'aise pour aller de l'avant avec l'immuabilité en 3.0.

@gabrielmaldi @wmertens Oui. C'était ça. Toutes mes excuses pour mon commentaire incohérent à la limite – j'ai clairement cliqué sur le bouton « Envoyer » sur un message à moitié écrit.

Pour rassembler certaines de mes pensées décousues :

  • Il y a clairement un certain intérêt pour les objets date immuables pour JS. Il existe des bibliothèques de dates immuables matures dans plusieurs autres langues, et il y a beaucoup d'élan général vers les objets immuables dans JS ( immutable.js a 10 500 étoiles si c'est une indication). À tout le moins, je pense que cela mérite une preuve de concept.
  • Malgré cet intérêt, très peu de code semble avoir été écrit. js-joda semble être la première tentative sérieuse d'écrire une bibliothèque de dates immuable pour JS.
  • Des moments immuables seraient un énorme changement de rupture, ce qui soulève des questions philosophiques. Bien que je détesterais perdre le soutien de la très grande communauté MomentJS, ce ne serait pas nécessairement une chose horrible pour ceux d'entre nous qui sont intéressés par des dates JS immuables de faire une rupture nette et de contribuer à js-joda au lieu d'essayer pour pousser un changement assez radical sur Moment (une bibliothèque mature avec une base d'utilisateurs importante et établie).
  • A part : js-joda est encore très jeune, et on ne sait pas quels sont les objectifs et les intentions de l'auteur pour la bibliothèque. En particulier, il doit choisir une licence, et nous pouvons vouloir déterminer si les besoins du développeur JS typique seraient satisfaits par une ré-implémentation fidèle de Joda Time ou JSR-310.

+1 pour une immutabilité, et le code plus sain qui en résultera.

Ce sera un effort majeur, alors un grand merci à ceux qui vont (et ont été) y arriver.

Moment est suffisamment utilisé pour que je pense qu'il serait possible d'opter pour quelque chose approchant ce qui suit, en supposant que le soit implémenté de la même manière que https://github.com/WhoopInc/frozen-moment de @butterflyhug

3.x : immuable en option, par défaut sur false, et avoir un indicateur défini sur l'exportation globale du moment qui serait défini sur true ; console.warn au chargement de la bibliothèque (en mode dev)
4.x : immuable en option, par défaut sur true, indicateur toujours disponible pour être défini sur false ; console.warn à propos de la planification pour 5.x (en mode dev)
5.x : immuable comme seul moyen

Ayez une page en amont et au centre décrivant la vision d'immuabilité à long terme - disons, une version majeure par an le long du contour 3.x/4.x/5.x que j'ai présenté - et je pense que cela donnerait un montant pour que toute personne concernée puisse mettre à jour son code.

Quelques remarques :

  1. J'ai construit WhoopInc/frozen-moment en espérant qu'un groupe de personnes ici pourraient être disposées à construire des choses avec, comme moyen de trouver des points problématiques dans l'écosystème du moment où l'immuabilité casserait les plugins, etc. Jusqu'à présent, peu de gens l'ont fait , ce qui m'a rendu moins désireux de travailler sur l'évangélisation des moments gelés et/ou de la communauté pour aider les auteurs de plugins à prendre en charge les moments immuables.

Cela dit, je suis toujours prêt à aider à corriger les bogues que les gens trouvent lors de l'utilisation de l'instant figé - peu importe si ces bogues sont les miens ou s'il s'agit d'un plugin d'un autre moment qui n'a jamais envisagé la possibilité que les moments deviennent immuables. Il suffit de signaler les problèmes au moment figé et j'y jetterai un coup d'œil. Et je pense toujours qu'un effort communautaire autour de quelque chose comme le moment figé pourrait nous aider à comprendre et à atténuer la douleur d'une transition vers des moments immuables.

  1. Si moment implémente l'immuabilité dans 3.0, il serait assez simple pour quelqu'un d'écrire et de maintenir un wrapper pour implémenter l'API 2.x de moment mutable au-dessus de l'API 3.x immuable. Conceptuellement, cela ressemblerait beaucoup à un moment gelé : partout où ce moment gelé implicitement clone() s, ce wrapper de mutabilité modifierait implicitement sa référence interne en une nouvelle valeur de moment immuable. Cela pourrait également aider à faciliter la transition pour les personnes utilisant moment dans de grandes bases de code.
  2. Je serais prêt à aider à réfléchir aux problèmes potentiels et à mettre en œuvre l'immuabilité au moment 3, si vous le souhaitez.
  3. js-joda portera directement JSR-310 dans JavaScript en utilisant une licence BSD .

@butterflyhug - Merci d'avoir

Je ne sais pas combien d'autres personnes ont pu avoir les mêmes processus de pensée.

Je suis curieux de savoir si les gens ici pensent que l'immuabilité devrait être explorée en conjonction avec la notion de rupture de la dépendance à l'objet Date (ou même en ajoutant une sorte d'évaluation paresseuse) pour des raisons de performances.

Je suggérerais de faire les choses étape par étape, @schmod. C'est déjà un (apparemment) grand changement

@RobertMcCarter Oui, je

+1 pour l'immuabilité, après une demi-heure passée à comprendre ce qui s'est passé avec mon application après la première utilisation de endOf(). Certes, je n'ai pas lu attentivement la documentation, j'ai juste supposé qu'une méthode avec ce nom renverrait la fin du mois par exemple, et laisserait l'instance du moment inchangée. Pour être honnête, c'est une surprise et je trouve ridicule que cela ne se passe pas de cette façon ou peut-être que ma tête est trop habituée aux énormes avantages -à mon avis- d'avoir une API -pour la plupart- immuable

+1 pour l'immuabilité :)

Je me fiche de l'immuabilité, laissez cette excellente bibliothèque tranquille !

@es6Test Pour quelles raisons n'êtes-vous pas d'accord avec l'immuabilité ? Avez-vous une raison concrète autre que la résistance au changement ?

+1
Je pense que cela facilitera l'utilisation de la bibliothèque si elle était immuable, mon code est plein de la méthode .clone () et parfois la mutabilité provoque des bogues très difficiles à trouver.

+1 S'il vous plaît, plus d'immuabilité ^_^

@danpantry Après avoir

Mais j'aimerais avoir encore quelques vars mutables, j'aime assez souvent ajouter des jours aux moments et je ne veux pas avoir à créer plus de vars pour conserver le résultat.

@es6Test Utilisez simplement let si vous ne l'aimez _vraiment_ pas ?

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

Je suis aussi en faveur de l'immuabilité. C'est la seule caractéristique de la bibliothèque datetime de Python qui la fait vraiment briller. Vous pouvez lancer des objets sans vous soucier de quelque chose qui les modifie, tout comme avec des chaînes de caractères.

Dans le monde React / Redux, l'immuabilité est primordiale. J'ai déjà rencontré des problèmes épineux parce que le moment n'est pas intrinsèquement immuable. La performance n'a pas d'importance ici car elle peut être atténuée. La bibliothèque ImmutableJs de Facebook prouve qu'immuable peut être fait sans sacrifier les performances.

Je vais également +1 sur l'immutabilité tout le chemin. Vous n'obtenez aucun avantage de l'immuabilité jusque-là, donc il ne sert à rien de faire à mi-chemin.

L'immuabilité et la programmation fonctionnelle sont plus utilisées que jamais (et j'adore ça). J'offrirai mon temps pour contribuer à cette initiative. Contributeurs s'il vous plaît contactez-moi et faites-moi savoir comment je peux être utile.

L'équipe voulait donner une mise à jour à ce sujet car nous avons eu tellement d'intérêt.

À ce stade, nous voulons que vous sachiez que nous avons entendu vos préoccupations. Toute l'équipe de mainteneurs convient que si nous écrivions la bibliothèque à partir de zéro, nous choisirions de la rendre immuable. Cependant, ce n'est pas comme ça en ce moment.

Dans l'état actuel des choses, nous avons 4 millions de téléchargements NPM par mois, ainsi qu'un nombre incalculable d'utilisateurs qui comptent sur l'instant via d'autres canaux. Tous ces utilisateurs ont un code qui s'attend à ce que le moment soit modifiable comme il l'est aujourd'hui. De plus, nous avons de nombreux plugins qui dépendent du moment mutable.

Le code est assez facile à écrire, mais les besoins de support de ce type de changement sont difficiles à assumer en tant que petite équipe faisant cela pendant notre temps libre. Cela dit, nous sommes prêts à l'envisager. On se demande quand même :

  • Pourquoi le plugin de moment gelé ne répond-il pas à vos besoins ?
  • Avez-vous juste besoin d'une API immuable (une API qui renvoie toujours un clone), ou devons-nous, pour une raison quelconque, vraiment ne pas muter les objets en interne ?
  • L'ajout d'une seconde API immuable au code actuel répondrait-il à vos besoins ?

Le problème avec le plugin de moment figé est qu'il s'agit d'un opt-in, pas d'un opt-out. Tous
moment() a besoin d'un .freeze() pour qu'il soit immuable.

Tout l'intérêt de l'immuabilité est que lorsque j'ai l'objet X, je sais que
à moins que je ne le rende explicitement modifiable, il doit être imperméable au changement.
Toute fonction publique qui me permet de modifier un objet en interne sans
la mutabilité explicite est problématique.

Je pense qu'une solution de contournement consiste à faire plusieurs choses:

  1. Ajouter une deuxième API immuable au code actuel
  2. Avoir un paramètre global moment() où s'il est défini sur le mode immuable, tout
    les instances moment() créées sont immuables, si un appel mutable est tenté,
    ne mutera pas et à la place une erreur avec un message approprié pour utiliser immuable
    appels API.

Cela, je pense, satisfera tout le monde. Qu'est-ce que tu penses?

Le lundi 23 mai 2016 à 12h11, Maggie Pint [email protected]
a écrit:

L'équipe voulait donner une mise à jour à ce sujet car nous avons eu tellement de
l'intérêt.

À ce stade, nous voulons que vous sachiez que nous avons entendu vos préoccupations. Les
toute l'équipe de mainteneurs convient que si nous écrivions la bibliothèque à partir du
à la base, nous choisirions de le rendre immuable. Cependant, ce n'est pas ainsi
c'est maintenant.

À l'heure actuelle, nous avons 4 millions de téléchargements NPM par mois, ainsi qu'un
nombre incalculable d'utilisateurs s'appuyant sur l'obtention du moment à travers d'autres
canaux. Tous ces utilisateurs ont un code qui s'attend à ce que le moment soit modifiable car
c'est aujourd'hui. De plus, nous avons de nombreux plugins s'appuyant sur le moment
mutable.

Le code est assez facile à écrire, mais le support a besoin de ce genre de
le changement sont difficiles à assumer en tant que petite équipe faisant cela dans notre réserve
temps. Cela dit, nous sommes prêts à l'envisager. On se demande quand même :

  • Pourquoi le plugin de moment gelé ne répond-il pas à vos besoins ?
  • Avez-vous juste besoin d'une API immuable (une API qui renvoie toujours un
    clone), ou devons-nous, pour une raison quelconque, vraiment ne pas muter en interne le
    objets?
  • L'ajout d'une seconde API immuable au code actuel répondrait-il à vos
    Besoins?

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/moment/moment/issues/1754#issuecomment-221062274

Eric Lau du compte Gmail.

Merci d'avoir répondu @maggiepint.

  1. Quelques problèmes avec le plugin de moment figé: ce n'est pas la valeur par défaut, il nécessite un travail supplémentaire à utiliser, il y a moins de chance qu'il soit activement maintenu, mon hypothèse est qu'il a un impact sur les performances (probablement un très petit) par rapport à quelque chose qui était construit comme immuable. Je pense que le plus gros problème est d'oublier de l'utiliser, en particulier sur des projets plus importants avec de nombreux ingénieurs.
  2. L'API doit être sans effet secondaire. Renvoyer un clone est bien, mais si vous modifiez également l'objet d'origine, ce serait un effet secondaire. Le code suivant ne doit pas modifier start lors de la déclaration de end :
start = moment();
end = start.add(10, 'minutes');
  1. Voulez-vous dire avoir des fonctions telles que « immutableAdd » en plus de « add » ? Si c'est le cas, alors oui techniquement, ce serait le cas, surtout si vous créez un wrapper pour utiliser des fonctions immuables utilisant les mêmes noms :
import "moment/immutable";
start = moment();
end = start.add(10, 'minutes'); // immutable version of add

À mon avis, cette approche se prête à une mise à niveau gracieuse pour ceux qui souhaitent utiliser l'API immuable - le code existant fonctionnera toujours, personne n'est forcé et nécessite moins de modifications pour ceux qui souhaitent utiliser l'API immuable.

Nous avons la ferme intention de rendre l'effet secondaire du code gratuit. Le modèle de base serait de se connecter aux fonctions actuelles, de les faire appeler clone, puis d'opérer sur ce clone.

Techniquement cependant, si vous créez du code vraiment immuable, les objets doivent être construits avec des valeurs qui ne changeront pas. Cela augmenterait cependant la difficulté de faire ce changement. C'est beaucoup plus facile d'appeler clone et de faire ce que nous faisions auparavant.

Je soutiens l'idée de Drew :

importer "moment/immuable" ;
début = moment();
end = start.add(10, 'minutes'); // version immuable de l'ajout

Ce serait formidable car il s'agit d'un opt-out immuable et aucun changement à
noms de fonction.

Le lundi 23 mai 2016 à 12h53, Maggie Pint [email protected]
a écrit:

Nous avons la ferme intention de rendre l'effet secondaire du code gratuit. Les bases
pattern serait de s'accrocher aux fonctions actuelles, de les faire appeler clone,
puis opérer sur ce clone.

Techniquement cependant, si vous créez du code vraiment immuable, les objets
doit être construit avec des valeurs qui ne changeront pas. Faire ainsi serait
augmenter la difficulté de faire ce changement cependant. C'est beaucoup plus facile de
appelez clone, puis faites ce que nous faisions auparavant.

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/moment/moment/issues/1754#issuecomment -221076796

Eric Lau du compte Gmail.

@ericlau-solide

  1. Avoir un paramètre global moment() où s'il est défini sur le mode immuable, tout
    les instances moment() créées sont immuables, si un appel mutable est tenté,
    ne mutera pas et à la place une erreur avec un message approprié pour utiliser immuable
    appels API.

Cela se brisera si 2 bibliothèques sur la page s'attendent à des comportements différents du moment. Par exemple, vous utilisez datepicker, qui attend un moment mutable, et votre propre code en attend un immuable -- cela ne fonctionnera pas.

Avoir une API immuable (ala-moment gelé)

Ce n'est pas non plus parfait, car aucun plugin de moment ne fonctionnera avec. En fait, il n'y a aucun moyen d'introduire l'immuabilité ET de garder tous les plugins existants fonctionnels. Les plugins ne fonctionneront pas du tout, ou ne fonctionneront pas avec des moments immuables, avant que quelqu'un ne passe le temps à les faire fonctionner.

importer "moment/immuable" ;

Il s'agit donc essentiellement de proposer une bibliothèque différente avec une interface similaire. Bien sûr, cela ne cassera pas le code, mais cela causera probablement de la confusion et fera que certains projets auront les 2 versions installées (par exemple, datepicker prendra la version mutable et votre code prendra la version immuable).

La meilleure option est de créer à peu près une API comme l'actuelle, mais avec des objets immuables. Une fourchette pourrait être en ordre. C'est la voie du logiciel libre après tout.

L'option "ajouter une deuxième API / publier un sous-module" serait la meilleure pour la compatibilité, car les développeurs pourraient mettre à niveau leur code de manière incrémentielle. Si possible, la signification de moment() (via import moment; dans module-land, ou le moment global dans la version du navigateur) ne devrait pas changer du tout, car il y a un tonne de code hérité là-bas.

OMI, une solution qui permettrait ce qui suit serait idéale :

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

Pas une bibliothèque différente, mais oui - ont deux types de moments séparés et distincts. En supposant que les objets moment mutables et immuables partagent une quantité importante de code "sous le capot", la taille de la bibliothèque n'aurait pas besoin d'augmenter beaucoup pour les développeurs qui ont besoin d'utiliser les deux syntaxes. Si une application n'utilise qu'une seule syntaxe, l' arborescence peut être utilisée pour produire une version optimisée.

Forker la bibliothèque doublerait potentiellement la taille du code que la plupart des développeurs devront charger, ce qui serait indésirable pour la plupart des applications Web.


Je ne pense pas que ce serait une bonne idée de supposer que tous les plugins fonctionneront avec des moments immuables "prêts à l'emploi", et je ne considérerais pas cela comme une exigence raisonnable.

Je ne pense pas non plus que ce soit une exigence/hypothèse raisonnable pour que les API mutables et immuables soient identiques. Nous devons nous efforcer de rendre le chemin de mise à niveau aussi fluide que possible, mais ne devons pas nous enfermer dans des syntaxes maladroites.


Je pense également qu'il y a beaucoup de place pour le débat/l'argumentation sur ce à quoi ressemblerait l'API "immuable". Modèle de constructeur ? Instanciation du constructeur ? Objet de valeur ? Implémenter l'API actuelle, mais des méthodes "setter" renvoient-elles un clone ?

Ma seule demande est que la nouvelle API soit claire et sans ambiguïté sur le type de moment avec lequel nous travaillons. OMI, freeze échoue à ce test et offre peu de protection au-delà d'appeler clone() chaque fois que je passe un moment.

Il s'agit donc essentiellement de proposer une bibliothèque différente avec une interface similaire. Bien sûr, cela ne cassera pas le code, mais cela causera probablement de la confusion et fera que certains projets auront les 2 versions installées (par exemple, datepicker prendra la version mutable et votre code prendra la version immuable).

Pas une bibliothèque séparée, juste une enveloppe mince autour de la même bibliothèque. Il n'y aurait besoin que d'une seule version de moment installée. Vous pouvez importer « moment/immuable » et le sélecteur de date peut importer « moment » dans le même projet sans problème.

Il pourrait y avoir un problème d'interfaçage avec des plugins qui prennent ou retournent un moment s'ils n'ont pas été mis à jour pour gérer des moments immuables.

Disons que vous passez un instant immuable à un plugin qui, à l'heure actuelle, le traite comme mutable. Jusqu'à ce que le plugin soit mis à jour, il devrait y avoir un moyen de convertir en mutable avant qu'un moment ne soit accordé au plugin. Idéalement, il serait déprécié après que les mainteneurs du projet aient eu le temps de prendre en charge l'immuabilité. Il faudrait aussi probablement un moyen de détecter l'immuabilité (pour les auteurs de plugins).

D'un autre côté, une bibliothèque qui se met à jour pour utiliser l'interface immuable et renvoie un moment immuable aux utilisateurs peut décourager ceux qui n'utilisent pas l'immuabilité et ne s'attendent pas à un moment immuable. Je pense que cela peut également être géré par une méthode de conversion déconseillée. Les plugins doivent renvoyer un moment du même type que celui transmis.

@maggiepint oui, je comprends votre point de vue, mais je pense que cela pourrait être un trop grand pas à faire. Personnellement, je serais d'accord avec une approche qui se contente de clone 's derrière le rideau. Surtout pendant que les problèmes sont réglés.

@tacomanator c'est aussi ce que je veux faire. Refaire le tout pour être vraiment immuable en interne n'est pas terriblement tenable.
Je ne savais tout simplement pas si, pour une raison quelconque, les gens VOULAIT cela.

@schmod Pourriez-vous expliquer brièvement pourquoi vous ne pensez pas que freeze est une API claire et sans ambiguïté ?

Si le nom de la fonction est trop mignon, je serais heureux de considérer un argument pour renommer les méthodes de Frozen Moment comme un problème sur ce référentiel. D'un autre côté, si vous ne pensez pas qu'il devrait être possible de passer de mutable à immuable (et inversement), alors je soupçonne que cela pourrait susciter une discussion ici - bien que notez que je serais également prêt à prendre Frozen Moment dans cette direction si nous obtenons un consensus approximatif que ce serait une meilleure API.

@maggiepint Ai-je raison de lire "ajouter une deuxième API immuable au code actuel" en regroupant essentiellement une partie ou la totalité de Frozen Moment avec la bibliothèque principale ? Si cela peut être utile, je serais heureux d'aider à migrer Frozen Moment ou certaines de ses idées dans l'organisation du moment (soit en tant que plugin officiel ou dans le cadre de la bibliothèque principale) et d'aider à sa maintenance dans ce nouveau contexte.

@butterflyhug Vous dites exactement ce que pensait @ichernev . Il se penchait sur le plugin officiel fourni avec la bibliothèque. Peut-être pourrions-nous nous coordonner à ce sujet dans Gitter à un moment donné ? Je dois m'absenter pendant trois jours pour affaires, donc j'aurai une disponibilité limitée. Le reste des gars devrait être là.

@papillon

Je pense que freeze est un bon nom, ça craint de devoir se rappeler de l'utiliser après _chaque_ invocation de moment.

Je pense aussi que import 'moment/immutable' a les mêmes problèmes, il est facile de l'oublier.

Honnêtement, vous suivez semver, je pense que la bonne approche est de faire en sorte que tout utilise _par défaut_ immuable et de publier ce changement comme sa propre version majeure, avec un plan pour ne plus prendre en charge les anciennes versions après une période de temps (12 mois ?). Les nouvelles fonctionnalités / correctifs pourraient être fusionnés dans les deux pistes, immuables et modifiables, avec un plan de migration donné aux utilisateurs utilisant la version modifiable.

Après les 12 mois susmentionnés, les anciennes versions fonctionneraient _toujours_, mais elles ne recevraient aucun TLC.

Bien sûr, c'est beaucoup de frais généraux, mais je pense qu'il vaudrait mieux faire ce changement correctement que d'essayer de le truquer dans l'intérêt de la rétrocompatibilité. Cela rend également le changement beaucoup plus compliqué, ce qui peut dissuader l'équipe de développement de base. Je ne sais pas.

Un autre inconvénient potentiel de cette approche est que les utilisateurs utilisent ce script à partir d'un CDN et ne spécifient pas de version explicite (pour une raison quelconque), ce qui peut entraîner la rupture de leurs sites si une API rétrocompatible est publiée. Tout ce que je peux dire, c'est "je vous l'avais dit", mais je comprends que ce risque ne soit pas acceptable pour le moment.

Avoir deux versions de la même bibliothèque ne serait un problème que si vous comptez sur un objet global et qu'il n'y a pas vraiment de moyen de contourner cela autre que de continuer à utiliser freeze() .


TLDR semble-t-il que le problème que vous essayez de résoudre est résolu par semver, que vous utilisez déjà. Pourquoi ne pas l'utiliser comme il se doit ? Version majeure pour les changements de rupture. La seule fois où cela casse, c'est lorsque vous comptez sur une variable globale moment et que vous utilisez un CDN, mais tout changement que nous apportons ici le cassera de toute façon

Mon vote porte également sur la version 3.0 semver et immuable.

Je ne m'oppose pas au nom freeze , mais je trouve qu'il est intrinsèquement problématique qu'il soit difficile de faire des suppositions sûres pour savoir si un moment est gelé ou non. ( Object.freeze() a un problème similaire)

Un moment immuable ne doit pas être ingelable, et il ne doit jamais y avoir de doute quant à savoir s'il est gelé ou non. Cela pourrait être accompli via une variante stricte du modèle de constructeur (c'est-à-dire que l'objet _only_ a des setters jusqu'à ce que .build() soit appelé, après quoi il _only_ a des getters), ou avoir un moment "gelé" dès que il est instancié, avec tous les setters renvoyant un clone.

Par exemple:

/* 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

Le premier exemple ressemble beaucoup à Java, mais laisse également peu d'ambiguïté sur la façon dont les moments sont construits et sur ce que vous pouvez en faire. Il fournit également un chemin efficace et intuitif pour construire de nouveaux moments avec peu de frais généraux, et suit de près la façon dont la plupart des gens utilisent actuellement le moment.

Je serais favorable à ce que les setters sur les moments construits lancent des exceptions, car ce comportement réduirait encore l'ambiguïté (au détriment de la verbosité) et obligerait les développeurs à reconnaître chaque fois qu'ils créent de nouveaux moments.

Le deuxième exemple semble avoir beaucoup plus de frais généraux, car nous créons (et supprimons) beaucoup d'objets. Mais, il y a beaucoup de place pour l'optimisation. La GC moderne est plutôt bonne ; une évaluation paresseuse pourrait aider; nous pourrions rendre les objets Moment aussi légers que possible (en supprimant le Date sous-jacent), etc. (Pour une comparaison, ce modèle n'est pas différent de la façon dont les chaînes sont gérées en JavaScript)


Je suis un fan de semver, mais le cas d'utilisation du navigateur rend les changements de rupture problématiques, car il sera impossible d'avoir deux versions de moment sur la même page sans module-loader.

Comme mentionné précédemment, il existe _beaucoup_ de code hérité qui dépend de Moment. À tout le moins, nous avons besoin d'une version qui prend en charge les deux modèles, pour permettre une période de transition en douceur.

+1 pour les méthodes composables qui renvoient de nouveaux moments. Je m'en fiche même s'ils sont immuables. Donnez-moi simplement la composition, afin que je puisse enchaîner les méthodes ensemble, ou attribuer le moment muté sur une seule ligne (au lieu de 2).

@alexyuly pourquoi le fonctionne- t-il pas pour vous ? Si vous voulez composer en ligne, vous pouvez faire quelque chose comme :

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

Ou peu importe.

@maggiepint Eh bien, je me sens http://momentjs.com/docs/#/manipulating/start -of/ <- aucune mention d'une valeur de retour.

Petite mise à jour - ce billet de blog est MA position sur cette question en ce moment : https://maggiepint.com/2016/06/24/why-moment-js-isnt-immutable-yet/

Je ne parle pas pour le reste de l'équipe, mais ils l'ont vu, et je dirais généralement que nous sommes tous dans un endroit similaire.

@maggiepint des points géniaux et très valables

Merci pour cela. L'immuabilité est reine dans le redux, je vais donc passer à js-joda à coup sûr. Je peux encore garder le moment pour le temps relatif.

Eric Lau - Gmail

Le vendredi 24 juin 2016 à 11:12 -0700, "Maggie Pint" [email protected] a écrit :

Petite mise à jour - ce billet de blog est MA position sur cette question en ce moment : https://maggiepint.com/2016/06/24/why-moment-js-isnt-immutable-yet/

Je ne parle pas pour le reste de l'équipe, mais ils l'ont vu, et je dirais généralement que nous sommes tous dans un endroit similaire.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub ou coupez le fil de discussion.

Quelques bugs/confusions plus typiques causés par la mutation : http://stackoverflow.com/questions/26131003/moment-js-start-and-end-of-given-month

+1 pour cela, mais en fait avec Redux, j'ai trouvé que c'était un problème étonnamment petit car je ne mets pas du tout d'instances Moment dans l'objet d'état Redux. Seules les chaînes de date ou les horodatages et j'utilise Moment dans les méthodes de rendu uniquement pour convertir les chaînes de date en d'autres chaînes.

Je le fais principalement parce qu'il est alors facile de sérialiser et de désérialiser l'état sans aucun travail supplémentaire, mais cela cache également bien la mutation de React et Redux.

Je fais de mon mieux pour vous donner une mise à jour sur celui-ci ce week-end. Nous avons un plan, mais je dois m'assurer que tout va fonctionner avant de m'y engager. Malheureusement, je déménage de Minneapolis à Seattle la semaine prochaine, donc cela peut ralentir pendant un certain temps, mais je veux faire avancer les choses.

Petite mise à jour en préparation d'une mise à jour plus importante, car j'ai remarqué que cet article de blog reçoit toujours du trafic. Je suis actuellement en train de retravailler le build de moment pour utiliser Babel. Cela nous permet d'intégrer le plugin de @butterflyhug dans le référentiel principal et de le rendre officiellement pris en charge. Dans le processus, nous allons nettoyer certaines choses sur le plugin. @butterflyhug nous a très gracieusement aidé avec cela. De plus, je rencontre John-David Dalton de LoDash (nous travaillons tous les deux chez Microsoft) pour discuter de stratégie lors de l'introduction d'un plugin officiel, comme il l'a déjà fait avec LoDash fonctionnel. Long article de blog et RFC à venir.

@maggiepint tout en rendant le moment gelé officiellement pris en charge, prévoyez-vous de vous adresser à https://github.com/WhoopInc/frozen-moment/issues/20 ?

Je pense que cette approche de l'immuabilité est suffisante tant que chaque appel à moment() renvoie un moment figé par défaut, et les développeurs n'ont pas à se souvenir d'appeler .freeze() chaque fois.

@gabrielmaldi Bonne question. J'écris la RFC (devrait être fait n'importe quel jour maintenant), et oui, c'est mon objectif explicite de fournir une meilleure histoire pour une utilisation immuable uniquement. Ma proposition va dans le sens de mon commentaire sur WhoopInc/frozen-moment#20, en tenant compte des méthodes statiques. Je posterai un lien vers mon RFC ici et dans ce numéro lorsque j'ouvrirai mon PR contre le référentiel RFC, et nous serions certainement heureux de recevoir les commentaires de la communauté sur la proposition à ce moment-là.

J'ai fini d'écrire le projet de RFC et ouvert un PR .

C'est un document assez long, en partie parce qu'il y a encore quelques questions en suspens sur la façon dont nous voulons fournir cette fonctionnalité aux utilisateurs et j'essaie donc de mettre en évidence les avantages et les inconvénients des différentes approches. Mais je pense que les idées de mise en œuvre sont assez solides, donc j'aimerais entendre les gens ici si vous avez des réserves sur l'API proposée pour l'utilisateur .

Résumé exécutif du RFC avec nos principales questions auxquelles il faut répondre : https://maggiepint.com/2016/07/16/immutability-its-happening/

@maggiepint J'ai essayé de poster un commentaire sur cet article, mais pour une raison quelconque, il a été avalé. Voici ce que j'ai écrit :


Ma plus grande préoccupation avec ces changements est qu'ils répondent à une partie disproportionnée et expressive de la communauté - évitant le rempart silencieux des développeurs ordinaires qui ne sont même pas conscients que cette discussion a lieu.

Les fils de discussion de GitHub ne sont pas un microcosme de la communauté de développement au sens large. Ce site souffre du même biais de participation que de nombreux forums sur le Web, et est orienté vers un certain type de développeur : intellectuellement engagé dans la théorie de l'informatique ; intéressé par les idées plutôt que par les applications ; et oserais-je même dire socialement enclin à se rallier aux tendances populaires. Ces développeurs sont naturellement attirés par des causes philosophiques célèbres comme l'immuabilité et la programmation fonctionnelle, et ont un accès plus proche de vous que tout autre groupe. Ils seront la voix la plus forte de la salle, et ils réclameront ce changement - mais qu'en est-il du reste du monde ?

Le monde entier veut des trucs qui marchent. Il veut savoir que la bibliothèque qu'il utilise actuellement continuera à recevoir des mises à jour - au moins des corrections de bugs, mais idéalement de petites améliorations incrémentielles qui améliorent leur vie. Mais il ne le dit pas, car il ne recherche pas activement ces forums, et parce qu'il faut une peau épaisse pour dénoncer la tendance.

Si vous avez l'intention de changer, je pense que vous devrez expliquer très clairement à ces personnes pourquoi ce changement améliorera leur vie ; pourquoi ils devraient mettre à niveau ; pourquoi ils n'ont pas à s'inquiéter que leurs projets hérités ne reçoivent pas de corrections de bogues indirectes ; et essentiellement - quelles choses ils seront maintenant capables de faire qu'ils ne pourraient pas actuellement.

Je pense aussi que vous devriez également être très prudent pour valider l'importance de ce changement en termes réels. Je me demande si vous devriez publier ce changement en tant que plugin ou wrapper, et surveiller attentivement son utilisation pendant plusieurs mois avant de le fusionner dans le tronc. Si l'immuabilité a été sur-représentée comme une préoccupation de niche, vous aurez trouvé un moyen de satisfaire ces utilisateurs vocaux sans changer le cours de la bibliothèque dans son ensemble.

En tant que premier utilisateur, j'ai terminé ici après un certain temps perdu avec startOf endOf. Ces méthodes sont étonnamment en mutation !

+1 pour l'immuabilité totale

Peut-être qu'une autre solution consiste à rendre douloureusement évident que les objets dans momentjs sont mutables . La documentation le mentionne dans la section sur le clonage, mais ce n'est PAS assez saillant.

Une autre solution, si vous voulez la mutabilité, utilisez des concepts orientés objet et créez une création d'objet en utilisant le mot-clé NEW vs le modèle d'usine moment().

Le monde entier veut des trucs qui marchent.
... vous devrez expliquer très clairement à ces personnes pourquoi ce changement améliorera leur vie

Tout le monde que j'ai vu être nouveau à un moment tombe dans le piège des "moments" en train de muter.
Même après 3 ans d'utilisation, je dois toujours me dire "oh merde, vous utilisez .startOf ici .. mieux vaut vérifier deux fois si vous avez besoin d'une copie".

Le comportement actuel n'est pas intuitif et cela se fait attendre depuis longtemps.
Essayez de faire muter array.filter/map et voyez à quel point c'est amusant.

Concernant...
Performance/Mémoire : Je n'ai jamais enchaîné plus de 2 funcs en un instant et généralement c'est .set().get()
Pseudo-immutabilité : il faudra de nombreuses générations jusqu'à ce que le java-pass-by-ref-gen soit sorti.

J'aime l'idée de @AdamHess de choisir si vous recherchez la POO ou l'immuabilité.

Mes deux cents sur la raison pour laquelle nous sommes confus sont les suivants : valeurs de retour. Si moment.add('1', 'days') renvoyait undefined, comme le font généralement les fonctions mutables dans JS, alors la confusion disparaîtrait. Rendre le même objet, pour moi du moins, implique que j'ai une nouvelle copie. Bien sûr, cela briserait la chaînabilité.

Je pense qu'il y a une faible probabilité de rencontrer des problèmes d'utilisation de la mémoire pour plus de développeurs (sauf pour des cas d'utilisation spéciaux). La mutabilité de Moment m'a déjà mordu. Les dates doivent être traitées comme des valeurs comme une chaîne ou un nombre.

+1 pour immuable par défaut

Ce même problème existe pour PHP, soit dit en passant. Voulez-vous être comme PHP ?! ??

En PHP, ils le résolvent en fournissant DateTimeImmutable (en plus du DateTime normal).

Si nous ne modifions pas le comportement par défaut pour qu'il soit immuable, nous devrions au moins envisager une API alternative de première classe comme imoment / momenti (ou autre). Je l'utiliserais littéralement toujours (sur l'API mutable) et j'espère que toute autre bibliothèque que j'utiliserais utiliserait également la version/API immuable.

Je vote aussi pour l'immuabilité, je suis prêt à aider à la mise en œuvre si c'est le plan. J'ai déjà rencontré des problèmes de mutabilité lors de l'addition et de la soustraction, ce qui le rend encore plus déroutant, c'est que ces méthodes renvoient l'instance à cause du chaînage.

Au fait, qu'en est-il des durées de clonage ? Quelle est la meilleure façon de le faire, je n'en ai pas trouvé qui ne se sente pas piraté.

@ngerritsen Je pense que la meilleure option disponible est moment.duration(existingDuration) .

Re : mise en œuvre, #3548 est toujours un PR actif. Espérons qu'il ne reste plus beaucoup de travail au niveau du code, mais cela ne fait jamais de mal d'avoir plus d'yeux pour valider de gros changements. Nous devons également travailler sur la documentation, etc. avant de pouvoir effectuer une modification majeure de la version, ce qui sera nécessaire pour publier un changement comme celui-ci. Si vous souhaitez aider avec l'une de ces listes, je suis sûr que nous vous en serions reconnaissants. ??

Je viens de passer une heure à essayer d'identifier un bug subtil causé par la mutation de .startOf() à la date d'origine... Merci pour le travail acharné, momentjs a fait un excellent travail en montrant comment créer une excellente bibliothèque de dates pour JS, mais je change à ce jour-fns en raison de la nature très subtile de ce type de bugs et parce qu'après mon introduction à certains concepts généraux de FP (principalement grâce à React, Redux et ELM), j'ai commencé à apprécier les avantages généraux de l'immuabilité.

Pour ce que ça vaut, lodash a déjà suivi une approche plus FP avec lodash/fp. Je suggérerais de jeter un œil à la façon dont lodash/fp a été implémenté car ils enveloppent leurs fonctions existantes au lieu d'avoir à tout réécrire. Les gars de Lodash sont également très très préoccupés par la performance.

Je suis également d'accord avec @mull , le vrai problème est dû à l'API de chaînage pour moi, qui IMO a quelques gros défauts de conception non seulement dans ce cas mais plus généralement (par exemple jQuery). Je serais mieux pour moi si les dates de mutation de méthode retournaient indéfinies (du moins c'est la règle générale que j'applique au code que j'écris)

Alors que l'espace de noms moment.frozen est en préparation, je recommanderais - comme le suggérait l'affiche précédente - d'utiliser simplement date-fns .

Je viens de corriger un autre bug dû à des moments mutables 🎉

Tangentiellement lié, ce serait génial si la 3.0 pouvait passer aux classes ES6 :

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

Une telle démarche pourrait également guider la discussion sur l'immuabilité. Je dirais que toutes les méthodes devraient être immuables à une exception près. Une méthode appelée .set('minute/hour/year/etc', 18) .

Je viens de commencer à utiliser Moment et j'étais _horrifié_ que cette bibliothèque ne soit pas entièrement immuable dès le départ. J'utilise moment-immuable jusqu'à ce que cela soit corrigé.

Le moment

Découvrez leur nouveau projet : luxon
C'est très agréable, moderne, immuable (!) Et devrait fonctionner bien mieux que moment-immuable qui enveloppe tout dans des appels .clone() .

Pour ceux qui souhaitent passer de momentjs à une approche moderne, veuillez consulter https://github.com/you-dont-need/You-Dont-Need-Momentjs

Très surpris qu'il soit mutable !

Jusqu'où luxon est-il un remplaçant? L'une des raisons pour lesquelles j'utilise Moment.js est la prise en charge du fuseau horaire - c'est un must pour mon projet.

@alamothe Cette question est clairement répondue sur le site : https://moment.github.io/luxon/docs/manual/moment.html

En fermant ça. Comme d'autres l'ont souligné, utilisez Luxon si vous voulez une API essentiellement immuable. Merci.

Cette page vous a été utile?
0 / 5 - 0 notes