Au-delà de Javascript – Synthèse

Cet article synthétise les travaux de veille technologique entrepris autour du thème des nouvelles technologies alternatives à Javascript.

 Javascript : vue d’ensemble, limites et défauts

Aujourd’hui, la technologie Javascript jouit d’une grande popularité dans les développements d’applications web modernes : non seulement le langage lui-même, qui s’est imposé comme le langage de script de référence pour le web, mais aussi les nombreux outils basés sur Javascript (bibliothèques, frameworks, méthodes AJAX). Javascript offre un moyen simple d’augmenter le dynamisme et l’interactivité d’un site. De plus, sa communauté est active, comme en témoigne d’ailleurs le nombre important de bibliothèques et frameworks qui étendent les possibilités du langage.

Cependant, Javascript souffre de défauts non négligeables. Par exemple, les mécanismes d’héritage, basés sur les chaînes de prototypes et non les classes, sont assez laborieux. Le langage permet une grande permissivité et réserve de nombreuses surprises, notamment en ce qui concerne la déclaration des variables et la gestion de leurs types. Ce qui peut rendre les tâches de déboggage très délicates. La syntaxe de Javascript, inspirée des langages tels que C ou Java, n’est pas adaptée à sa vraie nature, qui se rapproche davantage de langages fonctionnels comme Lisp ou Scheme, selon Douglas Crockford. De plus, le comité ECMA, qui pilote la conception du langage, a déjà publié de nombreuses versions de Javascript, ce qui entretient une certaine confusion. D’ailleurs, malgré de nets progrès ces dernières années, les principaux navigateurs web présents sur le marché ont des implémentations différentes du langage (browser quirks), ce qui complexifie les développements. Enfin, Javascript pâtit de mauvaises pratiques, passées ou toujours en vigueur : récupération et exploitation abusives de données personnelles, surgissement de fenêtres intempestives, surcharge des capacités de calcul ou des temps de chargement côté client et détériotation de l’expérience utilisateur pour les non-voyants.

Technologies alternatives à Javascript

Il existe de nombreuses bibliothèques et de nombreux frameworks basés sur Javascript, principalement dédiés aux développements d’applications web riches (RIA), comme en témoigne le site du projet TodoMVC. Il existe également des langages alternatifs qui, tout en conservant une syntaxe relativement proche de Javascript, entendent le dépasser. Ces langages sont souvent compilables en Javascript, à l’image de TypeScript, CoffeeScript et Dart.

CoffeeScript

CoffeeScript est un langage de programmation issu d’un projet open source, à typage dynamique faible (comme Javascript) et multi-paradigme. Il est pensé comme une tentative de révéler le meilleur de Javascript le plus simplement possible. Il permet d’utiliser toutes les bibliothèques Javascript existantes. Bien qu’il n’apporte ni méthode ni objet nouveau, CoffeeScript est tout de même pensé pour remédier aux défauts de syntaxe de Javascript et le rendre “plus simple et plus sûr”.

CoffeeScript apporte aussi des fonctionnalités nouvelles inspirées de langages comme Python, Ruby ou Haskell : sucre syntaxique, filtrage par motif ou listes en compréhension.

CoffeeScript propose un code qui se veut élégant mais qui n’est pas pour autant plus facile à lire ou à écrire car il se destine à des développeurs familiers de Javascript et ayant une certaine connaissance du langage Ruby. De plus, CoffeeScript est basé sur la programmation fonctionnelle et semble moins adapté à la programmation web orientée objet qu’un langage comme Dart.

Dart

En 2011, Google a dévoilé le projet Dart : un langage largement basé sur Javascript fourni avec différents outils de développement, dont un EDI, un SDK et un compilateur vers JavaScript. Il existe une différence majeure entre CoffeeScript et Dart : tandis que le premier tend à promouvoir les meilleurs aspects du Javascript, le second entend le remplacer.

Zoom sur Dart

Motivation

Dart est né à partir du constat, fait par Google, que les problèmes inhérents à la nature de Javascript ne peuvent être résolus en le faisant évoluer. Le projet Dart vise donc à créer un langage facile à apprendre, plus performant et prédictible, offrant plus de sécurité et capable d’être utilisé aussi bien sur de petits projets que sur de larges applications.

Le langage Dart

Afin de rendre le projet attrayant et de faciliter la prise en main du langage, Dart s’inspire de concepts familiers aux développeurs Javascript, C# et Java. En fait, Dart regroupe des concepts empruntés à de nombreux langages : la syntaxe de Javascript, les types optionnels à la manière de Strongtalk, les objets sur le modèle de Smalltalk, certains concepts tirés de C# et un mécanisme de parallélisme inspiré par Erlang.

De manière générale, Dart est un langage orienté objet à héritage simple, basé sur les classes, qui se veut moins permissif que Javascript et sans surprise. D’autre part, Dart apporte ou revoie des fonctionnalités par rapport à des langages comme Javascript ou C# : portée lexicale, types statiques optionels, types génériques covariants, constructeurs nommés, appels en cascade, capture des variables de boucle (closures), absence de conversions implicites, etc. Enfin, toutes les bibliothèques et API Javascript sont utilisables en Dart.

Les outils de développement Dart

Le projet Dart propose également un panel d’outils destinés à former une plateforme complète pour les développements web : un EDI, un SDK, un navigateur web dédié, un compilateur Dart vers Javascript, une machine virtuelle standalone, un gestionnaire de paquets et des mécanismes de déploiement et d’optimisation du code source.

Évolutions du projet

Les développements autour du projet Dart se poursuivent. En effet, depuis 2011, Dart a connu deux mises à jour importantes : Dart’s Milestone 2 et 3. Sortie en décembre 2012, la Dart M2 apporte une large documentation avec tutoriels ainsi que des améliorations majeures de certaines fonctionnalités : réduction importante de la taille du code généré par le compilateur vers Javascript, amélioration des bibliothèques et du gestionnaire de paquets et support du SSL par la machine virtuelle. En février 2013 est parue la Dart M3, principalement consacrée à la programmation asynchrone et à la gestion des événements (nouvelle API dédiée et améliorations de l’existant).

Les critiques

Aujourd’hui, le développement de Dart continue mais il est trop tôt pour avoir une idée de la réussite de cet ambitieux projet. A cet égard, Dart est l’objet de nombreuses critiques, notamment en ce qu’il entend constituer un énième standard de langage web. Une autre critique visant le projet Dart concerne sa conception en dehors d’un consensus, à l’encontre du développement de l’open-web. Certains développeurs craignent une forme d’appropriation de la technologie Javascript par Google.

Plan du rapport

En conclusion de ces travaux de veille technologique, nous publierons un rapport PDF qui reprendra tous les points abordés précédemment. Voici un aperçu de son plan :

Le Javascript

Origine et nature du langage

Limites et défauts

Mauvaise conception du langage
Disparités des versions et des implémentations
Mauvaises pratiques
Multiplication des extensions

Technologies alternatives

Vue d’ensemble

Le projet CoffeeScript

Le projet Dart

Zoom sur le projet Dart

Raison d’être

Le langage Dart

Les outils de développement Dart

Évolutions et perspectives du projet

Critiques

Conclusion

 

Licence Creative Commons
Cet article est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 France.

Les outils de développement Dart

Introduction

Dans l’article précédent, nous avons passé en revue les principales caractéristiques du langage Dart : sa nature, sa syntaxe, ses concepts et les langages dont ils sont inspirés, sans oublier un aperçu de quelques fonctionnalités intéressantes qui le démarquent de Javascript.

Toutefois, le projet Dart n’a pas pour seul objet la conception d’un langage : il concerne également un ensemble d’outils de développement, de programmes et de bibliothèques qui complètent et étendent le simple langage de programmation et visent à en accélérer la diffusion. Il semble évident que cette panoplie d’outils sert principalement à allécher les développeurs en facilitant la transition de leur langage d’origine vers Dart. Cela correspond aux desseins de Google qui prévoient de fédérer une communauté de développeurs suffisamment importante autour de la technologie Dart afin de supplanter, à terme, Javascript en tant que standard pour le développement d’applications web. Lire à cet égard l’introduction de notre précédent article.

Cet article sera donc en grande partie consacré à la description de ces outils qui constituent l’environnement de développement autour du langage Dart. Il fera ensuite allusion aux dernières évolutions du projet, puis il conclura sur une analyse plus critique de Dart en présentant les arguments de ses détracteurs.

 

 

Les outils de développement

Au-delà du langage qui promeut la simplicité, la performance et l’extensibilité, le projet Dart c’est aussi un EDI, Dart Editor, un SDK, un navigateur, un compilateur vers Javascript, un gestionnaire de paquets et une machine virtuelle.


Logo de Dart Editor – version M2

Les concepteurs de Dart ont affirmé leur souhait de délivrer une plateforme complète de développement web en plus d’un langage adapté. Ils mettent en avant des critères tels que la rapidité d’exécution et de démarrage des applications, le fait de disposer d’outils puissants pour développer et analyser ces applications ainsi qu’une très bonne intégration au DOM (l’API normalisée qui décrit les objets de la structure arborescente d’une page web et les moyens d’intéragir avec ces objets).

Principes de déploiement et d’exécution


Déploiement et exécution d’une application Dart – source : vidéo Google I/O 2012

Le schéma ci-dessus illustre les différentes manières de déployer et d’exécuter une application Dart. Cette dernière est représentée par les cadres verts : le code source et les bibliothèques associées. Plusieurs options s’offrent ensuite au développeur :

  • exécuter directement l’application sur Dartium, le navigateur web dédié à Dart qui embarque nativement la machine virtuelle,
  • ou traiter l’application à l’aide d’outils spécifiques :
    • typiquement, le compilateur Dart vers Javascript qui traduit le code Dart vers un unique fichier Javascript, ce qui rend l’application exécutable dans n’importe quel navigateur moderne,
    • ou encore convertir l’application et ses bibliothèques en une snapshot : c’est une version sérialisée, sous forme binaire, de la structure de l’application qui permet d’améliorer les performances au lancement car elle contient des données pré-analysées (plus besoin d’analyser la syntaxe ni de segmenter le code lors du lancement). De plus, une snapshot est complètement indépendante de la plateforme cible.

Compilateur Dart vers Javascript

La plateforme Dart offre un compilateur de Dart vers Javascript : le programme dart2js, écrit en Dart. Il est intégré au SDK et est utilisable en ligne de commande. Toutefois, l’outil en ligne de commande ne fait que lancer la version Dart du compilateur avec la machine virtuelle. Donc, une propriété anecdotique mais intéressante de ce compilateur est qu’il peut se compiler lui-même vers Javascript, étant écrit en Dart. Ce compilateur génère du code Javascript exécutable sur n’importe quel navigateur moderne, dont Internet Explorer 9 et 10, Safari, Firefox, Chrome, iOS Safari et Chrome pour Android.

Exemple de compilation :

main() {
  var list = makeList();
  var sum = 0;
  for (var i = 0; i < list.length; i++) {
    sum += list[i];
  }
  print(sum);
}

makeList() {
  var result = new List(100);
  for (var i = 0; i < result.length; i++) {
    result[i] = i;
  }
  return result;
}

Le code Dart ci-dessus est traduit après compilation par le code Javascript ci-dessous. Toutefois, la totalité du fichier Javascript généré compte près de 2000 lignes qui fournissent la traduction de  mécanismes importés de Dart (structures de données, opérateurs, méthodes, etc.) :

$.main = function() {
  var list, t1, sum, i, t2;
  list = $.makeList();
  if (typeof list !== "string" &&
      (typeof list !== "object" || list === null ||
      list.constructor !== Array &&
      !list.$isJavaScriptIndexingBehavior))
    return $.main$bailout(1, list);
  for (t1 = list.length, sum = 0, i = 0; i < t1; ++i) {
    t2 = list[i];
    if (typeof t2 !== "number")
      throw $.iae(t2);
    sum += t2;
  }
  $.Primitives_printString($.CONSTANT0.toString$0(sum));
};

$.makeList = function() {
  var result, t1, i;
  result = $.List_List(100);
  for (t1 = result.length, i = 0; i < t1; ++i)
    result[i] = i;
  return result;
};

On note que la méthode main fait appel à la méthode main$bailout. La version bailout (de secours) d’une méthode est une version non optimisée appelée dans certains cas par la version optimisée. Elle ne fait aucune supposition sur le type des paramètres et leur applique uniquement des opérations génériques. Le recours à la version de secours est nécessaire en cas d’optimisation hasardeuse (mauvais types, opérateurs ou méthodes non disponibles pour un objet, etc.) dont la validité n’est pas garantie. Son détail n’est pas donné ici.

Le tree shaking

La nature déclarative de Dart rend possible le tree shaking : c’est un mécanisme de pré-déploiement qui, en partant de la méthode main, détecte tout ce que l’application n’utilise pas (méthodes, classes, bibliothèques) et le supprime du code sources de l’application finale. Ce mécanisme est utilisé par le compilateur dart2js. Ainsi, les performances de l’application déployée, en Dart ou en Javascript, ne sont pénalisées que par ce que le programme utilise vraiment. Cela contribue à réduire les temps de chargement et de lancement de l’application.

L’EDI Dart Editor

Pour faciliter la prise en main et la diffusion de Dart, ses concepteurs ont tenu à développer un EDI dédié au langage : Dart Editor. Au téléchargement, Dart Editor embarque le SDK (et la machine virtuelle standalone qui va avec), l’EDI lui-même, accompagné de quelques exemples, et le navigateur web Dartium utilisé pour exécuter les applications Dart.

C’est un EDI léger qui permet de gérer des projets et offre quelques fonctionnalités classiques : navigation dans le code, remaniement du code, complétion automatique, déboggage et différents modes d’exécution des applications. Il existe des plugins de Dart Editor pour les EDI IntelliJ et WebStorm de JetBrains’ ainsi que pour l’EDI Eclipse.

Le SDK

Le SDK est un ensemble de programmes en ligne de commande et de bibliothèques. Les bibliothèques Dart permettent notamment le développpement d’applications web, tant du côté client que du côté serveur. Les outils en ligne de commande comprennent le compilateur dart2js vu plus haut et deux outils décrits ci-après : la machine virtuelle Dart standalone (autonome) et le gestionnaire de paquets Dart.

La machine virtuelle et le navigateur Dartium

La machine virtuelle peut être utilisée telle quelle (version standalone) en ligne de commande : c’est un des outils inclus au SDK. Elle permet donc d’exécuter des applications en ligne de commande Dart et propose deux modes d’exécution : production et checked (pour les tests et les développements). Contrairement à la JVM, le fonctionnement de cette machine virtuelle n’est pas basé sur l’utilisation d’un code semi-compilé (bytecode), mais directement sur du code source Dart. Cette page explique les raisons techniques qui ont motivé ce choix.

Par ailleurs, la machine virtuelle Dart est nativement incluse dans le navigateur web dédié aux applications Dart : Dartium, un navigateur basé sur Chromium. Par conséquent, pour les développements, l’avantage de ce navigateur est qu’il permet d’exécuter directement des applications Dart sans les compiler en Javascript.


Aperçu du navigateur Dartium exécutant une application web Dart

Gestionnaire de paquets

Enfin, la plateforme de développement Dart comprend un gestionnaire de paquets dédié au langage, baptisé pub. Il sert à réutiliser du code existant en tant que bibliothèque (library package) ou à empaqueter des applications (application package : paquet qui n’est pas destiné à servir de dépendance). Il permet donc la création et la publication de paquets et gère les versions (possibilité de mise à jour) et les dépendances entre paquets. Exécuté en ligne de commande ou dans l’interface de Dart Editor, il permet à partir d’un fichier descriptif (format YAML) d’importer automatiquement dans le code source d’une application toutes les dépendances nécessaires à sa bonne exécution.

 

 

Dart aujourd’hui et ensuite ?

Dart’s Milestone 2

En décembre 2012, Google a sorti la version 2.0 (Beta) du Dart SDK : Dart M2 pour Dart’s Milestone 2. Google a présenté la M2 comme un ensemble de nouvelles fonctionnalités qu’il serait plus juste de qualifier d’ensemble d’améliorations majeures des fonctionnalités existantes.
Parmi ces améliorations citons :

  • Réduction importante de la taille du code généré par dart2js et abandon du support de fonctionnalités obsolètes en Dart telles que #import, === ou !==
  • Corrections et améliorations des bibliothèques de base
  • Simplifications importantes de la bibliothèque html
  • La machine virtuelle Dart supporte désormais le SSL et donc le https
  • Large documentation et tutoriels intégrés pour les habitués de la programmation orientée objet mais débutant en développement web
  • Améliorations majeures apportées au gestionnaire de paquets, notamment dans le cadre du développement collaboratif

Dart’s Milestone 3

Le 20 février 2013 (mercredi dernier), Google a annoncé le lancement de la Milestone 3 du Dart SDK. Cette nouvelle version fournit une API dédiée à la programmation asynchrone et une meilleure gestion des événements. Dans ce cadre, de nouvelles classes sont apparues (ou alors d’anciennes classes ont été largement modifiées), les plus notables étant :

  • La classe Iterable prend une plus grande importance puisqu’elle devient la classe ancêtre des collections (comme List et Set). Iterable est une interface pratique fournissant un itérateur (Iterator) sur une collection d’objets.
  • La classe Stream fait son apparition dans la M3. Un Stream est une séquence d’événements asynchrones. Les événements peuvent être n’importe quels objets dans Dart, ce qui rend la classe Stream très versatile. Les streams peuvent être facilement transformés, filtrés, traités comme des pipes. Il s’agit surtout de pouvoir gérer facilement et de manière uniforme les événements comme un clic :
query('#button').onClick.listen((e) => submitForm());
  • L’utilisation de la classe Future a été facilitée. Cette classe permet de délayer un calcul en repoussant l’obtention d’une valeur pas encore disponible.
  • Certaines des modifications apportées n’étant pas retro-compatibles, l’équipe de développement attire l’attention des développeurs sur la fonctionnalité Clean-Up de Dart Editor qui permet de rendre compatible avec la nouvelle API un code développé sous l’ancienne. Voici une impression d’écran de Clean-Up à l’œuvre :


Source : dartlang.org

Cette dernière mise à jour apporte son lot de corrections et d’améliorations et prétend ainsi répondre aux demandes de la communauté de développeurs Dart. La simplification, l’optimisation, l’ajout de tutoriels et de fonctionnalités pratiques se veulent autant de réponses à ces demandes.

 

 

Analyse critique

Bien que le projet semble alléchant, avec un langage apparemment abouti et des outils de développement bénéficiant de la puissance d’innovation de Google, certaines personnes, à l’image de Jon Brodkin dans un article sur arstechnica.com, font remarquer que le fait que Google propose un outil qui permette de compiler du code Dart en Javascript est un frein au développement du projet, puisque même les développeurs qui auront fait le choix du langage Dart pourront toujours déployer leurs applications en Javascript, tandis que l’inverse n’est pas faisable. Notons que les programmes écrits en CoffeeScript, pour être exécutés, compilent également vers Javascript, comme nous l’avions mentionné dans deux précédents articles : ici et.

Microsoft en particulier critique les raisons même de la création de Dart. En effet, Google affirme que Javascript présente trop de défauts fondamentaux et que Dart est la rupture nécessaire en termes de syntaxe comme de compilation/exécution. Pour l’équipe Javascript de Microsoft, ceci est une erreur. Microsoft a en effet travaillé sur une autre alternative à Javascript : TypeScript qui, d’après eux, ne renie pas la syntaxe de Javascript (comme Dart, GWT…). Cependant, comme le résume Peter Bright, TypeScript partage quelques idées avec Dart (types statiques optionnels par exemple) tout en n’étant pas suffisamment ambitieux, ce qui, ajouté à des problèmes de développement, a tué le projet dans l’œuf.

Mais, la plus large partie des critiques adressées à Dart concerne la multiplication des standards en compétition par la création de nouveaux standard supposés remplacer les précédents. Le dessin humoristique ci-dessous illustre avec ironie ce problème récurent :


Source : xkcd.com

D’après Oliver Hunt, ingénieur chez Apple sur le projet WebKit, l’apparition d’un nouveau langage web non standardisé va à l’encontre du développement de l’open web en échappant à toute forme de consensus. Il insiste aussi sur l’appropriation de la technologie Javascript par Google. En effet, d’après Brendan Eich, qui a développé Javascript et travaille pour Mozilla, ni Opera ni Mozilla ne supporteront la machine virtuelle Dart. Dart ne fonctionnerait (du moins efficacement) que dans Chrome, ce qui représenterait un pas de plus vers la fragmentation.

 

 

Sources :

Javascript as a compilation target – Making it fast, Florian Loitsch, Google

Vidéo google I/O 2012

Licence Creative Commons
Cet article est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 France.

Le langage Dart

Pourquoi Dart ?

Peu après que Google a dévoilé le projet “Dash”, ancêtre de Dart, lors d’une conférence tenue le 12/10/2011, un document interne à Google a fuité sur le web. Dans ce long email décrivant le projet “Dash”, des employés de Google affirment que les problèmes inhérents à la nature de Javascript ne peuvent être résolus en le faisant évoluer. Ils présentent alors Dash comme un Javascript plus performant, capable d’être utilisé sur des projets à grande échelle et offrant une meilleure sécurité. A la question “Pourquoi contourner les processus standards ?” (d’évolution de Javascript et de normalisation), ils répondent : “Any effort with the historic baggage that Javascript has will be extremely limited.  We need to make a clean break, make progress, and then engage the community.

Il est dur voire impossible de prédire les performances d’un programme écrit en Javascript, d’autant plus qu’il y a une grande variabilité selon les navigateurs (voir Figure 1). Le développement d’une application très performante en Javascript n’est donc pas aisé. Dart prétend y remédier en n’utilisant que la partie de Javascript qui est prédictible (en complexité, temps de réponse…) et efficace (rapide).


Figure 1 : évolution des performances de Javascript sur différentes plateformses

La plateforme Dart se fixe les objectifs suivants :

  • Fournir un langage de programmation très facile à apprendre, à l’instar de Javascript, et qui permette aux développeurs une grande productivité et une grande modularité.
  • Autoriser aussi bien le développement de petits projets (pour les passionnés, par exemple) que le développement d’applications à grande échelle (typiquement les applications de Google comme Gmail).
  • Offrir des performances élevées et prédictibles.
  • Permettre de lancer très rapidement des applications lors de leur premier chargement sur le client (pas plus de 100 ms au démarrage).
  • Assurer la compatibilité du langage avec tous les navigateurs modernes en mettant notamment à disposition des développeurs un traducteur Dart vers Javascript.

Le langage Dart

Dart agrège différents aspects à partir de différents langages de programmation. Il est en effet basé sur la syntaxe de Javascript, utilise les types optionnels à la manière de Strongtalk, les objets sur le modèle de Smalltalk, certains concepts tirés de C# et un modèle d’Isolates inspiré par Erlang (les Isolates sont des sortes de fils d’exécution, comparables aux workers en Javascript). Comme indiqué plus haut, une idée importante soutenant son développement est de le rendre attrayant et très facile à apprendre, d’où l’utilisation de syntaxes et concepts familiers aux développeurs Javascript, C# et Java.
Dart est donc un langage de programmation orienté objet, à héritage simple basé sur les classes, utilisant des interfaces, proposant une syntaxe familière, mono-threadé mais offrant un mécanisme de parallélisme (basé sur les Isolates). Par rapport à Javascript, il cache moins de surprises et est moins permissif. Cette page donne une vue générale des différences entre Dart et deux autres langages que sont Javascript et C#.

Portée lexicale

Le lexical scoping (portée lexicale des variables) est une des idées au cœur du développement de Dart. Les créateurs ont délibérément conçu une syntaxe qui utilise abondamment les accolades : cela montre une rupture avec les langages tels que Python ou Ruby et un retour aux langages tels que Java. La portée d’une variable se voit simplement aux accolades qui l’entourent, la valeur de cette variable sera donc celle attendue.

Types statiques optionnels

Un autre point fondamental de Dart concerne les types statiques optionnels :

Exemple 1 : une classe Point sans types statiques

class Point {
  var x, y;
  Point(this.x, this.y);
  operator +(other) => new Point(x + other.x, y + other.y);
  toString() => "($x,$y)";
}
main() {
  var p = new Point(2, 3);
  print(p + new Point(4, 5));
}

Exemple 2 : le même code avec types statiques

class Point {
  num x, y;
  Point(this.x, this.y);
  Point operator +(Point other) => new Point(x + other.x, y + other.y);
  String toString() => "($x,$y)";
}
main() {
  Point p = new Point(2, 3);
  print(p + new Point(4, 5));
}

On peut noter l’utilisation de l’interpolation de chaînes dans la méthode toString(). Par ailleurs, le constructeur ne peut pas être appelé sans le mot-clé new.

Les types statiques sont optionels dans Dart. Cela donne le choix aux développeurs, en fonction de leurs habitudes ou de leurs besoins : ils peuvent se passer des annotations et signatures de type pour développer rapidement de petits programmes ou des prototypes, mais ils peuvent aussi s’en servir pour rendre leur code plus clair et mieux documenté, surtout dans le cas d’applications modulaires complexes. Ainsi, un programme modeste peut ne pas avoir d’annotation de type tout en se réservant la possibilité d’en rajouter. Les types rendent l’intention du développeur plus claire ce qui aide les humains ou les outils informatique à comprendre le code. Les types statiques optionnels servent donc de documentation pour le code et les interfaces. Ils peuvent être génériques ce qui les rend utiles pour les collections. Par exemple, si une Pomme est un Fruit, alors une liste de Pommes est une liste de Fruits. Ce genre de types génériques covariants n’est par exemple pas disponible en Java ou C#.

Exemple 3 : type générique covariant

main() {
  List<Apple> apples = tree.pickApples();
  printFruits(apples);
}
void printFruits(List<Fruit> fruits) {
  for (Fruit each in fruits) print(each);
}

Constructeurs nommés

Dart permet de nommer des constructeurs car le langage n’intègre pas la surcharge de types. Cela évite d’utiliser des méthodes factory comme intermédiaires pour arriver au même résultat.

Exemple 4 : constructeur de Point via des coordonnées polaires

class Point {
  var x, y;
  Point(this.x, this.y);
  Point.polar(r, t) : x = r * cos(t), y = r * sin(t);
}
main() {
  var p = new Point(2, 3);
  var q = new Point.polar(3, 0.21);
}

Interfaces avec implémentations par défaut

Cette fonctionnalité de Dart permet d’utiliser des interfaces sans vraiment avoir à connaître les types d’implémentation qu’elles utilisent, ce qui est notamment pratique pour les novices. Dart autorise l’utilisation du mot-clé new pour ses interfaces, comme le montre l’exemple ci-dessous. Dans cet exemple, une première liste sans paramètre générique est créée, donc l’appel au constructeur est délégué à l’implémentation par défaut, qui dans ce cas est ListFactory. On crée ainsi une liste susceptible d’accepter n’importe quel objet. La deuxième liste en revanche est construite en utilisant le type Point, elle n’acceptera donc que des Points.

Exemple 5 : interface pour les listes

interface List<E> implements Collection<E> default ListFactory<E> {
  List([int length]);
  ...
}
main() {
  var untyped = new List();         // any object can be added
  var typed = new List<Point>(12);  // only points can be added
}

On peut noter les crochets dans la signature du constructeur de liste : ils signifient que le paramètre entier length est optionnel.

Appels en cascade

Cette fonctionnalité importée de Smalltalk permet de procéder à de multiples appels sur un même objet, et ce de manière chaînée. Cela simplifie l’écriture et permet d’éviter la création de nouvelles variables locales. L’exemple ci-dessous illustre l’utilisation de ces appels en cascade sur l’objet context pour dessiner un cercle.

Exemple 6 : appels en cascade sur un objet

void drawCircle(CanvasElement canvas, int x, int y, int size) {
  canvas.context..beginPath()
                ..arc(x, y, size, 0, Math.PI * 2, false)
                ..fill()
                ..closePath()
                ..stroke();
}

Capture des variables de boucle

Dans de nombreux langages, le code ci-dessous affiche 55555 car les fermetures (closures) font toutes référence à la même variable i. Avec Dart, en revanche, chaque fermeture fait référence à une copie de la variable i qui est capturée à chaque tour de boucle, ce qui donne le résultat attendu : 01234.

Exemple 7 : capture du compteur lors de la définition de closures

main() {
  var closures = [];
  for (var i = 0; i < 5; i++) closures.add(() => i);  // collect
  for (var c in closures) print(c());                 // evaluate
}

Ce genre de situation est connu pour engendrer beaucoup d’erreurs en Javascript. La capture en bonne et due forme des variables de boucle peut être d’une grande aide dans la définition de gestionnaires d’événements sur des listes d’éléments HTML, par exemple.

Autres caractéristiques de Dart

  • Toutes les bibliothèques et API Javascript sont utilisables dans Dart. D’ailleurs la gestion des dépendances et bibliothèques se fait automatiquement (téléchargement automatique). Cette possibilité émane de la volonté de Google de remplacer Javascript par Dart en rendant le passage à Dart encore plus aisé.
  • Il n’y a pas de conversions implicites donc la sémantique est claire.
  • Les bibliothèques Dart sont en lecture seule donc on peut faire confiance aux composants construits à partir de ces bibliothèques.

Source :
Vidéo google I/O 2012

Licence Creative Commons
Cet article est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 France.

Au-delà de Javascript – CoffeeScript et Dart

Suite et fin sur CoffeeScript

Revenons sur CoffeeScript.
Rappelons tout d’abord que le code CoffeeScript est compilé en JavaScript. Cela a l’avantage de rendre tout code JavaScript compatible avec des travaux entrepris sur CoffeeScript.
Le langage ajoute en fait du sucre syntaxique inspiré par des langages comme Python ou Ruby afin d’améliorer la brièveté et la lisibilité du JavaScript, tout en ajoutant des fonctionnalités comme le filtrage par motif ou les listes en compréhension.

Le sucre syntaxique est une expression qui désigne des extensions faites à un langage de programmation ne modifiant pas son expressivité mais le rendant plus agréable à la lecture comme à l’écriture. Par exemple, en C la notation tableau[i] est un exemple de sucre syntaxique pour l’expression *(tableau+i), qui évite au programmeur de recourir à l’arithmétique des pointeurs.
Le code qui suit illustre ces facilités d’écriture :

Le code CoffeeScript suivant :

square = (x) -> x * x
cube   = (x) -> square(x) * x

Compile comme cela en JavaScript :

var cube, square;
square = function(x) {
  return x * x;
};
cube = function(x) {
  return square(x) * x;
};

Source du code : http://coffeescript.org/

On observe évidemment une forte compression du code mais aussi une syntaxe très proche de Ruby ou Python.
Comme nous l’avons vu précédemment, les objets JavaScript sont basés sur des prototypes et non des classes et le mécanisme d’héritage, bien que fonctionnel, souffre d’une syntaxe très déroutante, qui pousse les développeurs à utiliser des astuces relevant du monkey patching.
L’exemple suivant montre le mécanisme d’héritage de CoffeeScript, bien plus “classique” puisque basé sur les classes :

class Animal
    constructor: (@name) ->

    move: (meters) ->
        alert @name + " moved " + meters + "m."

class Snake extends Animal
    move: ->
        alert "Slithering..."
        super 5

Source du code : http://coffeescript.org/

Le filtrage par motif est la vérification de la présence de constituants d’un motif par un programme informatique. Par exemple “travail*spatial” peut signifier toute chaîne de caractères commencant par “travail” et se terminant par “spatial”. Le mécanisme sous-jacent (dans un langage comme Haskel) est celui des Arbres/Expressions Rationnelles.

Enfin, CoffeeScript permet la définition de listes en compréhension (comme en Haskell et Python), c’est-à-dire des listes dont le contenu est défini par filtrage du contenu d’une autre liste. Par exemple pour créer la liste des 5 premiers entiers au cube :

list = [1, 2, 3, 4, 5]
cubes = (math.cube num for num in list)

Ou plus compact (les cubes de 10 à 1) :

cube_countdown = (math.cube num for num in [10..1])

Certaines limites de CoffeeScript

Ainsi, CoffeeScript a la prétention de proposer du “beau code” et de réduire la charge de travail du programmeur. Pour autant, le code produit n’est pas forcément plus facile à lire ou à écrire.
En effet, comme le souligne Benjamin Farrell dans le billet The CoffeeScript Dilemna de son blog : le code est plus lisible pour des développeurs possédant un background important en Ruby (CoffeeScript est issu de la communauté Ruby et sa syntaxe et ses mécanismes s’en inspirent fortement, comme nous l’avons vu).
D’autre part, Benjamin Farrell souligne une erreur à ne pas commettre : CoffeeScript s’adresse à des personnes ayant une bonne connaissance de JavaScript, pas à des débutants. Il ne serait pas efficace de l’utiliser en lieu et place de JavaScript lorsque l’on ne possède pas l’éxpérience nécessaire. CoffeeScript n’est donc pas une alternative complète à JavaScript.

Comme le souligne à plusieurs reprises Martin Heller dans son article intitulé Turn up your nose at Dart and smell the CoffeeScript paru en octobre 2011 sur JavaWorld.com, CoffeeScript reste basé sur de la programmation fonctionnelle alors que Dart – que nous présenterons dans la suite de cette étude – semble une meilleure alternative pour la programmation web orientée-objet.

Tandis que CoffeeScript ramène JavaScript dans une zone de confort pour les vétérans de Ruby (ou Python, Haskel, etc.), Dart, en s’attaquant au dynamisme (ou laxisme) de JavaScript et en le ramenant à un langage plus statique (d’après Jeremy Ashkenas), en fait un langage plus familier pour les dévelopeurs Java.

Par ailleurs, d’après Ryan Florence, la plus grande différence entre Dart et CoffeeScript est que ce dernier n’est pas une menace pour JavaScript car il se présente comme une évolution alors que l’objectif avoué de Dart est de remplacer JavaScript.

Introduction sur Dart

Dart désigne un langage de programmation web orienté object, basé sur les classes, à héritage simple, open-source et développé par Google. Le projet Dart, dévoilé en 2011 par Lars Bak et Kasper Lund, ne se limite pas au seul langage :

  • Dart Editor, un EDI léger qui permet de gérer des projets, offre des fonctionnalités classiques (complétion automatique, déboggage, etc.) et se décline en plugins pour IntelliJ et Eclipse notamment ;
  • un SDK contenant un ensemble de bibliothèques et des outils en ligne de commande ;
  • Chromium (ou Dartium), un navigateur web incluant une machine virtuelle, capable d’exécuter directement des programmes Dart, sans compilation vers Javascript ;
  • un compilateur Dart vers Javascript, écrit en Dart (qui peut donc se compiler lui-même en Javascript) ;
  • un gestionnaire de paquets de programmes Dart (dépôt public et outil en ligne de commande) ;
  • une machine virtuelle (outil en ligne de commande, intégrée à Dart Editor, au SDK et à Chromium).

La syntaxe de Dart est largement basée sur celle de Javascript. L’objectif de ce langage est de supplanter Javascript en tant que langage standard pour les développements web, tant du côté serveur que du côté client, adapté aux plus petits scripts comme aux plus larges applications. Dart prétend offrir le choix d’écrire du code typé ou non (mélange de résolution statique et dynamique), tout en étant plus rigoureux que Javascript sur la déclaration et la portée des variables. Il est également pensé pour être modulaire, utilisable avec de nombreuses bibliothèques, et comporte des mécanismes de parallélisme (Isolates).

Dans la suite de cette étude, nous reviendrons plus en détail sur le langage Dart, les défauts auxquels il apporte des solutions et ses perspectives. Nous donnerons également un aperçu d’autres technologies pouvant être présentées comme des alternatives à Javascript.

 

Licence Creative Commons
Cet article est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 France.

Les défauts de Javascript – A propos de CoffeeScript

Les défauts de Javascript

 Aberrations du langage

Les objets en Javascript sont basés sur des prototypes et non sur des classes. Cela est assez déroutant pour les développeurs habitués à une programmation orientée-objet plus classique, avec notamment des concepts de propriété propres ou de chaîne de prototypes.

Voici un exemple de mécanisme d’héritage en Javascript, tel que préconisé par le MDN*, avec correction du pointeur du constructeur de la classe dérivée pour parachever l’héritage :

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = new Person();

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true

L’exemple ci-dessous témoigne de la permissivité de Javascript au niveau de la gestion des variables (pas de déclaration nécessaire, etc.) :

<script>
 var str = "text";
 str.foo = 0;
 alert(str.foo);
</script>

Ce script, exécuté dans un navigateur moderne, affiche “undefined”, sans aucune erreur de la console Javascript lors de l’affectation de la valeur 0 à la variable str.foo.

L’exemple en ligne de commande ci-dessous montre la confusion qui peut exister entre les concepts de type et d’instance (opérateurs typeof et instanceof) :

> var a = new String();
> typeof a
object
> a instanceof Object
true
> typeof null
object
> null instanceof Object
false

Dans cet exemple, on se sert de null comme une référence pour récupérer la propriété d’un objet, alors que null n’est pas une référence :

> null=2;
Exception: ReferenceError: Left side of assignment is not a reference.
> a={};
[object Object]
> a["null"]="foo";
foo
> a[null]
foo

La syntaxe

La syntaxe JavaScript est-elle adaptée aux caractéristiques du langage ? Non, répond le créateur du langage CoffeeScript, Jeremy Ashkenas, qui lui reproche de venir de Java. Il qualifie d’ailleurs CoffeeScript de “Javascript pas fantaisiste”. Selon Ashkenas, la syntaxe de Javascript est laide car copiée sur Java et inadaptée à la véritable nature du langage. Nombreux sont ceux qui, effectivement, considèrent Javascript comme un langage raffiné mais mal servi. Cette critique est notamment formulée par un célèbre spécialiste de Javascript, Douglas Crockford, auteur de JavaScript : the good parts, traduit en français par “Javascript : gardez le meilleur”. Il existe des réflexions de la communauté de développeurs sur les manières d’adopter une syntaxe adaptée au langage (voir ce fil de discussion sur developpez.com).

D’après Jeremy Ashkenas : “L’idée de base c’est de dire que le noyau JavaScript ainsi que son modèle orienté objet ou fonctionnel sont vraiment très bons, mais que tout ça est caché derrière une syntaxe qui vient de Java, principalement. Le problème qui en découle c’est que cette syntaxe ne reflète pas les concepts profonds du langage”, sous entendu : la syntaxe de JavaScript n’est pas aussi élégante et aussi utile que ses concepts.

Dans le contexte d’un navigateur web

Dans la deuxième moitié des années 90 et jusqu’au début de la décennie 2000, Javascript, développé initialement par Netscape, avait pour principal concurrent le langage de script JScript d’Internet Explorer (IE). Ces deux langage sont des implémentations différentes de la norme ECMAScript, qui ont entraîné des divergences dans la gestion des scripts par les moteurs des navigateurs. Certaines méthodes comme celles dévolues à la gestion d’événements ou à l’ajout de texte dans les balises HTML ont ainsi longtemps différé entre IE et les navigateurs héritiers de Netscape, comme Firefox ou Chrome. Ces disparités tendent à s’effacer, simplifiant le travail des développeurs. Mais il n’existe pas d’harmonie parfaite pour ce qui est de l’implémentation de la totalité de la norme ECMAScript.

Par ailleurs, certaines méthodes Javascript de manipulation du DOM sont dangereuses à utiliser car elles ont des comportements inattendus (dans l’absolu ou d’un navigateur à l’autre) et peuvent détruire les propriétés des objets du DOM sur lesquels elles sont appliquées, à l’image de document.write(), qu’il est fortement conseillé d’éviter.

Mauvaises pratiques et prudence des internautes

La popularité de Javascript est en partie due à sa simplicité. Le fait qu’il ait été massivement adopté et utilisé pour rendre des sites plus interactifs a donné lieu à la multiplication de mauvaises pratiques qui rendent les internautes méfiants, parfois à raison.

Voici les principales raisons pour lesquelles les internautes peuvent être amenées à désactiver Javascript (voir cet article et cette discussion) :

  • Le Javascript est un langage « client », il permet de récupérer des statistiques sur les usages des internautes (avec tous les marqueurs statistiques Google Analytics et Xiti) mais aussi des informations sur la vie privée. Il peut être le vecteur de failles de sécurité qui permettent entre autres de récupérer l’historique ou les champs de formulaires enregistrés.

  • Javascript est également utilisé pour faire surgir des pop-ups publicitaires de manière intempestive, ce qui nuit à l’expérience utilisateur.

  • L’utilisation abusive des méthodes AJAX pour mettre à jour automatiquement tout ou partie des pages web peut engendrer le chargement d’importants flots de données à l’insu de l’utilisateur. Cela peut rendre les applications web gourmandes en bande passante.

  • Javascript est un langage interprété dont le chargement est long. Pour offrir plus de fonctionnalités ou accroître la fluidité d’utilisation, certains sites utilisent à outrance le Javascript, ce qui peut provoquer des temps de chargement conséquents et nuire à l’expérience utilisateur. Surtout si, côté client, la puissance de calcul n’est pas suffisante ou si le matériel ou le logiciel n’est pas assez récent.

  • Enfin, du Javascript utilisé à mauvais escient peut avoir des effets néfastes en termes d’accessibilité : les logiciels pour les non-voyants s’accommodent plus facilement d’un contenu brut (directement renvoyé par le serveur) que de pages complexifiées par les CSS ou les scripts.

Malgré ces critiques, Javascript reste un langage très utile pour programmer des fonctionnalités haut-niveau qui rendent les sites web plus simples d’utilisation et plus interactifs. La communauté Javascript semble active si on se réfère à l’agenda des événements du MDN, la dernière conférence en date [au 7 décembre 2012] dédiée à Javascript ayant eu lieu le 15 novembre à Sydney (Australie).

 

Une introduction sur CoffeeScript

CoffeeScript est un langage de programmation sous licence MIT, à typage dynamique faible (comme Javascript) et multi-paradigme. Il est pensé comme une tentative de révéler le meilleur de Javascript le plus simplement possible.

La règle d’or de CoffeeScript est : “C’est juste du Javascript”. Le code compile en son équivalent Javascript et il n’y a pas d’interprétation à exécution. On peut utiliser toutes les bibliothèques Javascript existantes depuis CoffeeScript et inversement.

En quoi il pallie certains défauts de Javascript

Pour remédier principalement aux défauts de syntaxe de Javascript, Jeremy Ashkenas a donc eu l’idée de lancer un projet open-source baptisé CoffeeScript. Il s’agit d’une variation de JavaScript avec une syntaxe qui reflèterait mieux ses caractéristiques. Avec un compilateur en Ruby, CoffeeScript n’apporte pas de méthode ou d’objet particuliers mais il compile directement en pur Javascript. Il offre également des tableaux de compréhension similaire à ceux de Python et fait des déclarations Javascript viables. Son créateur assure que son objectif est aussi de rendre Javascript plus simple et plus sûr : il affirme que “avec CoffeeScript, vous ne pouvez plus accidentellement créer une variable. Cette fonctionnalité amène plus de sureté au langage”.

 

* MDN : Mozilla Developer Network – site : https://developer.mozilla.org/fr/

 

Licence Creative Commons
Cet article est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 France.

Au-delà de Javascript – Justification de l’étude

Introduction

Nous rappelons que cette étude s’inscrit dans la continuité du projet de veille technologique mené en 2011-2012 autour de Javascript. Ce projet traitait principalement des API Javascript et de leur standardisation dans le cadre de la technologie HTML5. Il s’intéressait aux capacités de Javascript alors que nous nous intéresserons plutôt aux limites actuelles, évolutions futures et surtout aux alternatives à Javascript.

Utilisations de Javascript aujourd’hui

Selon Paul Andrew, les bibliothèques Javascript sont devenues fondamentales dans la conception de sites web, la plupart d’entre eux intégrant du code Javascript voire des méthodes Ajax. Il s’agit probablement du point central dans le développement du Web 2.0.

Bien qu’il soit tout à fait possible d’utiliser Javascript sans aucun framework, une étude de W3Techs.com montre que près de 60% des sites web utilisent au moins un des principaux frameworks traités ci-dessous :


D’autre part, le framework jQuery semble prépondérant puisque utilisé dans près de 53 % de l’ensemble des sites internet et possédant près de 90 % des parts de marché.

Cependant, il existe un grand nombre de frameworks Javascript. Nous en avons en effet recensés plus de 50.

Quelques défauts de Javascript

Malgré sa popularité et le fait qu’il s’appuie sur une norme bien établie (ECMAScript), le langage Javascript souffre de certains défauts que nous aborderons plus en détail dans la suite de notre étude. On peut noter entre autres : une grande permissivité, en particulier dans la gestions des variables et de leurs types, des usages datés quant à la manipulation des documents HTML (norme DOM 0), une implémentation nativement assez pauvre de la programmation orientée objet (recours à des librairies comme JS.Class ou Prototype.js) et le fait qu’il ait été pensé pour scripter des applications côté client (alternatives telles que Node.js pour le côté serveur).

Afin de pallier tout ou partie de ces défauts, certaines technologies émergent, notamment les langages Google Dart et CoffeeScript. Les prochains articles reviendront plus en détail sur le langage Javascript et ses failles, puis présenterons ses alternatives.

Auteurs : Nicolas Noël, Gaëtan Girin

Licence Creative Commons
Cet article est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 France.

Au-delà de Javascript – cadrage de l’étude

Le sujet de veille

Ce billet présente succinctement le sujet de veille technologique sur lequel nous travaillerons jusqu’au 8 mars 2013 et dont nous communiquerons l’avancement sur ce blog.

Ce sujet peut être vu comme le prolongement du projet de veille technologique mené en 2011-2012 autour de Javascript. Voici le plan retenu :

  • 1ère partie : Panorama général de la technologie Javascript, limites et évolutions souhaitables
  • 2e partie : Étude comparatives des alternatives à la technologie Javascript (langage Dart, autres ?)
  • 3e partie : Plongée plus en profondeur dans une des alternatives identifiées à la 2e partie.

Le contenu de la troisième partie dépendra fortement des conclusions de la deuxième. D’ici 2013, nous avons pour objectif de cibler la technologie à retenir comme alternative intéressante à Javascript.

Les rédacteurs

Nous sommes deux étudiants de l’École Centrale de Nantes (ECN) : Nicolas Noël et Gaëtan Girin. Nos travaux publiés dans le cadre de cette étude seront placés sous licence Creative Commons Attribution 3.0 France (CC BY 3.0).

Nous travaillerons sous la supervision de Morgan Magnin, maître de conférence au sein du département d’Informatique et de Mathématiques de l’ECN.