Follow me
RSS feed
My sources
My Viadeo

Objective-J

Greg | 20 Mar 2009

cappuccino1Ici commence notre voyage dans le monde merveilleux de Cappuccino.

Dans ce premier article, nous allons nous contenter de jouer avec Objective-J en dehors de toute application Web. En effet, même si Cappuccino est un framework Web, il n'en reste pas moins qu'il repose sur le langage Objective-J que nous pouvons utiliser sans forcement créer une application Web.

Objective-J, comme le laisse penser son nom, est une réécriture d'Objective-C pour Cappuccino qui est lui même un portage de Cocoa. Si nous faisons un parallèle, nous pouvons grossièrement dire que Cocoa repose sur Objective-C qui est une extension du C, alors que Cappuccino repose sur Objective-J qui est lui-même une extension de JavaScript. Nous n'allons pas entrer dans les détails de l'architecture de Cappuccino, mais sachant qu'il s'agit au final de JavaScript, vous allez voir que nous pouvons en utiliser toute la puissance, tout comme nous utilisons le C avec Objective-C.

Installation et test de Cappuccino

L'installation de Cappuccino est on ne peut plus simple. Commencez par télécharger les frameworks et outils. Inutile de prendre le Starter Package. Vous pouvez y jeter un oeil, mais en l'occurrence cet archive contient la documentation et le template d'application généré par défaut. Toutes choses que nous avons par ailleurs dans l'archive des frameworks et outils.

Une fois l'archive CappuccinoTools-X.X.zip téléchargée, décompressez là et utilisez votre shell préféré pour exécuter le script install-tools. Attention ce script doit être exécuté sous le compte root.

Par défaut, les outils et frameworks de Cappuccino sont installés dans /usr/local. Vous pouvez changer ce répertoire d'installation en utilisant l'option --prefix du script d'installation.

Une fois l'installation terminée, il vous sera demandé

Cappuccino étant installé, nous pouvons tester. Pour cela, nous allons créer une application Web1. Dans les faits nous allons utiliser l'outil steam qui permet de générer un template d'application.

$ steam create test
Setting up Rhino utilties
...
$ 

Une fois ceci fait, vous devez vous retrouver avec un répertoire test contenant les fichiers et répertoires suivants :
AppController.j
Frameworks/
Info.plist
index-debug.html
index.html
main.j

Ouvrez le fichier index.html avec votre navigateur préféré. Si après une courte attente vous voyez apparaître le message Hello World c'est que tout va bien !

Objective-J

Si vous avez déjà utilisé Objective-C, ce qui va suivre ne devrait pas vous poser de problème... Si ce n'est pas le cas, rien de grave. J'hésite cependant à vous dire que vos éventuelles connaissances en C, JavaScript ou développement objet devraient vous aider. Particulièrement en ce qui concerne l'objet, je ne ferais aucune explication, considérant que les notions qui s'y rapportent vous sont familières.

Les types

Objective-J ce veut être un langage typé (tout comme Objective-C). Ceci implique normalement que tous les identifiants possèdent un type. Donc, si nous voulons déclarer une variable, nous utiliserons la notation suivante :

id monObject

id représente ici le type. En fait id est un peu particulier dans le sens où il définit un type quelconque. Nous pouvons donc être plus précis en utilisant une des notations suivantes :

CPString maChaine

int monEntier

La différence entre les deux approches fait que dans le second cas, nous avons un typage statique. En effet, déclaré avec id, un identifiant peut faire référence à n'importe quel type d'objet. Ce n'est pas le cas si nous utilisons CPString, int ou tout autre type.

Dans la réalité, tout ce que je viens de dire est faut ! En effet, le typage statique n'est que cosmétique dans Objective-J. Souvenez-vous que nous somme au dessus de JavaScript. Or ce dernier est faiblement typé et Objective-J hérite de cette caractéristique.

Les messages

Pour demander à un objet d'exécuter une méthode, il faut lui envoyer un message2. Ceci se fait en utilisant une expression entre crochets :

[monObject monMessage]

En Objective-J, le message correspond toujours à un nom de méthode de l'objet récepteur. Si vous commencez à trouver un côté Lisp-ien à Objective-J, rassurez vous, vous allez voir que cette notation entraine d'énormes avantages. Pour le voir, regardons comment passer des paramètres. Dans un langage plus classique, vous avez l'habitude de passer des paramètres en utilisant la notation suivante :

monObjet.maMethode( parametre )

En Objective-J nous ferons le même appel de la façon suivante :

[monObjet monMessage:parametre]

Et alors me direz-vous ? Et alors allons plus loin. Imaginez que nous ayons une méthode prenant plusieurs paramètres. Prenons comme exemple le cas où nous avons une méthode permettant de passer le nom et le prénom d'un utilisateur et faisons en sorte que le nom de notre méthode soit parlant. Nous avons l'habitude de faire cela :

user.addFirstNameAndLastName( firstName, lastName )

En Objective-J nous ferons cela :

[user addFirstName:firstName andLastName:lastName]

N'est-ce pas beaucoup plus explicite (et naturel -- finalement) ?

Bien entendu, il est possible d'enchaîner les messages. Pour cela il faut imbriquer les expressions entre crochets :

[[monObject monPremierMessage] monSecondMessage]

Cette notation est équivalente à l'écriture :

id monAutreObjet = [monObjet monPremierMessage]

[monAutreObjet monSecondMessage]

Les méthodes

Maintenant que nous savons utiliser les messages, voyons comment créer des méthodes. Si vous avez compris l'intérêt de la notation crochet pour le passage de paramètres, vous pouvez facilement deviner comment nous allons définir des méthodes :

- (void)doSomething
{
  // Cette méthode ne prend aucun paramètre en ne retourne rien (void)
}

- (int)age:(id)dateDeNaissance
{
  // Cette méthode prend en paramètre un objet et renvoie un entier
}

- (id)areaWithWidth:(int)width andHeight:(int)height
{
  // Cette méthode prend deux paramètres entiers et renvoie un objet
} 

Tout cela est assez logique. La question qui se pose est le pourquoi du signe moins (-) en début de déclaration. En fait, il s'agit simplement de préciser que nous avons affaire à une méthode d'instance. Si nous voulons déclarer une méthode de classe, nous remplaçons ce moins par un signe plus (+).

+ (id)initWithWidth:(int)width andHeight:(int)height
{
  // ...
}

Les classes

Dans la majorité des langages objets compilés, nous avons l'habitude de distinguer la définition de l'interface d'une classe et son implémentation. En Objective-C par exemple, nous utilisons les mots clés @interface et @implement pour faire ces deux choses. Objective-J n'étant pas langage compilé3, la définition de l'interface ne sert à rien si l'implémentation ne lui est pas accolée.

La définition d'une classe Objective-J commence donc pas @implement, suivi du nom de la classe et de la classe dont elle hérite. S'en suivent les variables d'instance déclarées entre accolades. Viennent ensuite les définitions des méthodes. Puis nous terminons par @end. Voici un exemple :

@import <Foundation/CPObject.j>

@implementation User : CPObject
{
  CPString nom

  CPString prenom

}

- (id)init
{
  self = [super init]


  return self

}

- (void)setFirstName:(CPString)n
{
  prenom = n

}

- (void)setLastName:(CPString)n
{
  nom = n

}

- (void)hello
{
  print( "Bonjour "+prenom+" "+nom )

}
@end

Comme vous pouvez le voir, nous avons ajouté avant la définition de la classe User, via le mot clé @import, l'import du fichier Foundation/CPObject.j déclarant la classe CPObject. Ceci est obligatoire, car la classe User hérite de la classe CPObject définie dans Foundation/CPObject.j.

Pour tester notre classe, placez dans un fichier (User.j) le code précédent et créez un nouveau fichier (test.j) contenant le code suivant :

@import "User.j"

u = [[User alloc] init]

[u setFirstName:@"Grégoire"]

[u setLastName:@"Lejeune"]

[u hello]

Nous allons maintenant utiliser l'outil objj qui permet d'exécuter, via la ligne de commande, un script Objective-J :

$ objj test.j
Setting up Rhino utilties
Bonjour Grégoire Lejeune
$

Dans le fichier test.j vous remarquerez que nous n'avons pas typé u. En fait Cappuccino ne nous permet pas de le faire et écrire

User u = [[User alloc] init]

ou

id u = [[User alloc] init]

entraînerait une erreur. La seule solution, si vraiment vous souhaitez indiquer que vous avez affaire à une variable, c'est d'utiliser la notation :

var u = [[User alloc] init]

Vous ne pouvez typer que les variables d'instances lors de la déclaration d'une classe.

Constructeur

Revenons sur la création d'un objet User. Dans l'exemple nous avons utilisé la ligne suivant :

u = [[User alloc] init]

En fait, la création d'un objet à partir d'une classe se fait en deux temps. D'abord l'allocation (via alloc) puis l'initialisation (via init). L'allocation n'a pas vraiment de sens ici. En effet, il s'agit avant tout de copier Objective-C qui implique qu'un objet est en réalité un pointeur. En effet, si nous avions été en Objective-C nous aurions dû faire :

User *u = [[User alloc] init]

Avec Objective-J, l'allocation ne sert qu'à copier Objective-C. C'est l'initialisation qui est importante. Sachez que nous pouvons définir plusieurs méthodes d'initialisation. En voici une par exemple qui pourrait être intéressante :

- (id)initWithFirstName:(CPString)fn andLastName:(CPString)ln
{
  self = [super init]

	
  prenom = fn

  nom = ln

	
  return self
}

Nous somme maintenant capable de créer un objet User comme ceci :

u = [[User alloc] initWithFirstName:@"Muriel" andLastName:@"Oger"]

Ayant cela, nous pouvons simplifier la méthode init définie initialement :

- (id)init
{
  return [self initWithFirstName:@"" andLastName:@""]

}

Ce que nous venons de faire est plus sain dans le sens ou nous sommes certains que, quelle que soit la méthode d'initialisation utilisée, nom et prenom seront affectés.

Pour terminer ce point, mettons en place une méthode de classe :

+ (id)newUserWithFirstName:(CPString)fn andLastName:(CPString)ln
{
  return [[self alloc] initWithFirstName:fn andLastName:ln]

}

Avec cette méthode, nous pouvez éviter l'utilisation du alloc en créant un nouvel utilisateur de la façon suivante :

u = [User newUserWithFirstName:@"Maïa" andLastName:@"Oger--Lejeune"]

Fundation et AppKit

Lorsque nous avons fait l'import de CPObject.j nous avons utilisé le chemin Fundation. En fait, Cappuccino reprend tellement bien Cocoa, qu'il en copie l'architecture. En effet, il existe deux framework :

Vous trouverez la description complète de ces classes dans la documentation de Cappuccino.

La prochaine fois nous commencerons à jouer avec AppKit et nous créerons une application Web.

1 Et alors ? Je croyais que nous ne ferions pas d'application Web !!!
2 Normal !
3 - C'est pas vrai !
   - C'est pas faux !
   - Mais c'est pas vrai !
   - Mais c'est pas faux !

Copyright © 2009 - 2011 Grégoire Lejeune.
All documents licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License, except ones with specified licence.
Powered by Jekyll.