60

en fait, dans l'exmple de sally, le 2e a remplace le premier, le premier type n'existe plus...
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

61

pour reconnaitre les floats des int et des strings,
un tag pour les types simples est stocké dans la structure, cf les sources de la vm(moins gores que celles du compilo et de la lib/runtime, mais attention, des fois le comportement est pas tout à fait pareil),
je suis sur qu'ils auraient pu ne pas distinguer les floats en fait grin si ils définissent par exemple l'exposant sur un octet, alors ça compare d'abord l'exposant, ensuite, ça passe à la mantisse, ça devrait marcher trigic (bon j'ai pas trop réfléchi hein je dis probablement une grosse connerie...)
/* Structural comparison */ #define LESS -1 #define EQUAL 0 #define GREATER 1 #define UNORDERED (1L << (8 * sizeof(value) - 1)) /* The return value of compare_val is as follows:       > 0                 v1 is greater than v2       0                   v1 is equal to v2       < 0 and > UNORDERED v1 is less than v2       UNORDERED           v1 and v2 cannot be compared */ static intnat compare_val(value v1, value v2, int total) {   struct compare_item * sp;   tag_t t1, t2;   sp = compare_stack;   while (1) {     if (v1 == v2 && total) goto next_item;     if (Is_long(v1)) {       if (v1 == v2) goto next_item;       if (Is_long(v2))         return Long_val(v1) - Long_val(v2);       /* Subtraction above cannot overflow and cannot result in UNORDERED */       if ((Is_atom(v2) || Is_young(v2) || Is_in_heap(v2)) &&           Tag_val(v2) == Forward_tag) {         v2 = Forward_val(v2);         continue;       }       return LESS;                /* v1 long < v2 block */     }     if (Is_long(v2)) {       if ((Is_atom(v1) || Is_young(v1) || Is_in_heap(v1)) &&           Tag_val(v1) == Forward_tag) {         v1 = Forward_val(v1);         continue;       }       return GREATER;            /* v1 block > v2 long */     }     /* If one of the objects is outside the heap (but is not an atom),        use address comparison. Since both addresses are 2-aligned,        shift lsb off to avoid overflow in subtraction. */     if ((!Is_atom(v1) && !Is_young(v1) && !Is_in_heap(v1)) ||         (!Is_atom(v2) && !Is_young(v2) && !Is_in_heap(v2))) {       if (v1 == v2) goto next_item;       return (v1 >> 1) - (v2 >> 1);       /* Subtraction above cannot result in UNORDERED */     }     t1 = Tag_val(v1);     t2 = Tag_val(v2);     if (t1 == Forward_tag) { v1 = Forward_val (v1); continue; }     if (t2 == Forward_tag) { v2 = Forward_val (v2); continue; }     if (t1 != t2) return (intnat)t1 - (intnat)t2;     switch(t1) {     case String_tag: {       mlsize_t len1, len2, len;       unsigned char * p1, * p2;       if (v1 == v2) break;       len1 = caml_string_length(v1);       len2 = caml_string_length(v2);       for (len = (len1 <= len2 ? len1 : len2),              p1 = (unsigned char *) String_val(v1),              p2 = (unsigned char *) String_val(v2);            len > 0;            len--, p1++, p2++)         if (*p1 != *p2) return (intnat)*p1 - (intnat)*p2;       if (len1 != len2) return len1 - len2;       break;     }     case Double_tag: {       double d1 = Double_val(v1);       double d2 = Double_val(v2);       if (d1 < d2) return LESS;       if (d1 > d2) return GREATER;       if (d1 != d2) {         if (! total) return UNORDERED;         /* One or both of d1 and d2 is NaN.  Order according to the            convention NaN = NaN and NaN < f for all other floats f. */         if (d1 == d1) return GREATER; /* d1 is not NaN, d2 is NaN */         if (d2 == d2) return LESS;    /* d2 is not NaN, d1 is NaN */         /* d1 and d2 are both NaN, thus equal: continue comparison */       }       break;     }     case Double_array_tag: {       mlsize_t sz1 = Wosize_val(v1) / Double_wosize;       mlsize_t sz2 = Wosize_val(v2) / Double_wosize;       mlsize_t i;       if (sz1 != sz2) return sz1 - sz2;       for (i = 0; i < sz1; i++) {         double d1 = Double_field(v1, i);         double d2 = Double_field(v2, i);         if (d1 < d2) return LESS;         if (d1 > d2) return GREATER;         if (d1 != d2) {           if (! total) return UNORDERED;           /* See comment for Double_tag case */           if (d1 == d1) return GREATER;           if (d2 == d2) return LESS;         }       }       break;     }     case Abstract_tag:       compare_free_stack();       caml_invalid_argument("equal: abstract value");     case Closure_tag:     case Infix_tag:       compare_free_stack();       caml_invalid_argument("equal: functional value");     case Object_tag: {       intnat oid1 = Oid_val(v1);       intnat oid2 = Oid_val(v2);       if (oid1 != oid2) return oid1 - oid2;       break;     }     case Custom_tag: {       int res;       int (*compare)(value v1, value v2) = Custom_ops_val(v1)->compare;       if (compare == NULL) caml_invalid_argument("equal: abstract value");       caml_compare_unordered = 0;       res = Custom_ops_val(v1)->compare(v1, v2);       if (caml_compare_unordered && !total) return UNORDERED;       if (res != 0) return res;       break;     }     default: {       mlsize_t sz1 = Wosize_val(v1);       mlsize_t sz2 = Wosize_val(v2);       /* Compare sizes first for speed */       if (sz1 != sz2) return sz1 - sz2;       if (sz1 == 0) break;       /* Remember that we still have to compare fields 1 ... sz - 1 */       if (sz1 > 1) {         sp++;         if (sp >= compare_stack_limit) sp = compare_resize_stack(sp);         sp->v1 = &Field(v1, 1);         sp->v2 = &Field(v2, 1);         sp->count = sz1 - 1;       }       /* Continue comparison with first field */       v1 = Field(v1, 0);       v2 = Field(v2, 0);       continue;     }     }   next_item:     /* Pop one more item to compare, if any */     if (sp == compare_stack) return EQUAL; /* we're done */     v1 = *((sp->v1)++);     v2 = *((sp->v2)++);     if (--(sp->count) == 0) sp--;   } }
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

62

./60>
ben il "existe" encore, c'est juste qu'il n'est plus accessible par son nom... de même que si en C tu écris
[pre]int x; #define x y[/cite] alors x n'est pas accessible par son nom, mais il existe toujours... [cite]si ils définissent par exemple l'exposant sur un octet, alors ça compare d'abord l'exposant, ensuite, ça passe à la mantisse, ça devrait marcher #trigic#[/cite] pour que ça marche avec les nombres signés, il faudrait aussi que la mantisse soit inversée pour les nombres négatifs, mais à part ça oui ça pourrait marcher ^^ (je dis pas que ça serait rapide par contre #trinon# et de toute façon comme les deux ensembles sont totalement ordonnées et finis, les ordres sont isomorphes, donc moyennant 16 Go de ROM maximum c'est équivalent #trioui# [hum mais en fait les entiers sont seulement sur 31 bits, donc du coup on a pas assez de place pour stocker bijectivement un flottant, même 32 bit :p et puis les flottants de caml doivent être 64 bits, donc spa la peine d'y penser...])

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

63

Sally > Ben en fait je n'ai jamais fait d'OO à la caml, mais je pensais que ça marchait un peu pareil que java, non ? Ie quand on déclare une classe on déclare qu'elle hérite d'une autre, et dans ce cas toute fonction qui prend en argument la classe mère peut prendre la classe fille.
avatar
I'm on a boat motherfucker, don't you ever forget

64

[cite]Pollux :
./60>
ben il "existe" encore, c'est juste qu'il n'est plus accessible par son nom... de même que si en C tu écris
[pre]int x; #define x y[/cite] alors x n'est pas accessible par son nom, mais il existe toujours...[/cite] Oui, enfin il risque d'être garbage collecté du coup.
avatar
I'm on a boat motherfucker, don't you ever forget

65

Moumou :
Sally > Ben en fait je n'ai jamais fait d'OO à la caml, mais je pensais que ça marchait un peu pareil que java, non ? Ie quand on déclare une classe on déclare qu'elle hérite d'une autre, et dans ce cas toute fonction qui prend en argument la classe mère peut prendre la classe fille.


oui, c'est comme ça
par contre il n'y a pas de downcasting possible (sans Obj.magic)
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

66

Ben alors c'est bien du sous-typage. Enfin c'est ce que moi et le futur chef de Sally appelons du sous-typage hehe
avatar
I'm on a boat motherfucker, don't you ever forget

67

[cite]Moumou :
[cite]Pollux :
./60>
ben il "existe" encore, c'est juste qu'il n'est plus accessible par son nom... de même que si en C tu écris
[pre]int x; #define x y[/cite] alors x n'est pas accessible par son nom, mais il existe toujours...[/cite] Oui, enfin il risque d'être garbage collecté du coup. [/cite] non, le gc de caml est un gc à analyse de racine (il regarde si les valeurs ne sont plus pointées nulle part), et à générations (pour vérifier les valeurs de moins en moins souvent, une valeur de la première génération est checkée et si elle est checkée comme encore utilisée plus de x fois, elle passe dans la 2eme génération où elle est checkée très rarement (en fait presque jamais puisque il n'y a que 2 générations dans le gc de ocaml avec un gc mineur pour la 1ere gen et un gc majeur pour la 2e). il détecte si c'est un pointeur ou un int grace à un bit réservé. ça n'est pas un gc à comptage de références (auquel cas effectivement et avec un algo de merde, il pourrait passer au gc)
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

68

Moumou :
Ben alors c'est bien du sous-typage. Enfin c'est ce que moi et le futur chef de Sally appelons du sous-typage hehe


oui, mais pour l'objet, et les types simples ne sont pas des objets,
et il y a une défférence entre une classe mère / une classe fille et entre un int / un 'a.
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

69

Moumou :
Sally > Ben en fait je n'ai jamais fait d'OO à la caml, mais je pensais que ça marchait un peu pareil que java, non ? Ie quand on déclare une classe on déclare qu'elle hérite d'une autre, et dans ce cas toute fonction qui prend en argument la classe mère peut prendre la classe fille.

Oui voilà c'est un peu l'idée, mais malheureusement le typage a ses limitations :

# class chaine =
    object(self)
      method longueur = 42
    end;;
class chaine : object method longueur : int end
# class caractere =
    object(self)
    method   longueur = 1
      method nom_unicode = "HOT BEVERAGE"
  end;;
  class caractere :
  object method longueur : int method nom_unicode : string end
# let paire_vers_liste x y = [x;y];;
val paire_vers_liste : 'a -> 'a -> 'a list = <fun>
# let nimportequoi_vers_chaine c = (c:>chaine);;
val nimportequoi_vers_chaine : #chaine -> chaine = <fun>
# let caractere_vers_chaine (c:caractere) = (c:>chaine);;
val caractere_vers_chaine : caractere -> chaine = <fun>
# let fonction (x:chaine) (y:caractere) = paire_vers_liste x y;;
This expression has type caractere = < longueur : int; nom_unicode : string >
but is here used with type chaine = < longueur : int >
Only the first object type has a method nom_unicode


Bref, c'est un peu dommage que l'appel de paire_vers_liste ne soit pas capable de se rendre compte que x et y sont tous les deux des #chaine, et donc qu'on peut appeler paire_vers_liste avec 'a = chaine et les casts kivonbien sad Du coup un caractère n'est pas *vraiment* une chaîne...
(menfin ils ont sûrement leurs raisons, calculabilité du typage, rétrocompatibilité, etc...)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

70

Et bien sûr que si il y a du downcasting possible sans Obj.magic, heureusement triso (c'est l'upcasting qui n'est pas possible)

Le problème, c'est pas qu'il n'est pas possible, c'est plutôt que l'inférence de type n'est pas toujours capable de le faire tout seul et qu'il faut l'"aider" avec :>...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

71

Pollux :
Et bien sûr que si il y a du downcasting possible sans Obj.magic, heureusement triso (c'est l'upcasting qui n'est pas possible)

Le problème, c'est pas qu'il n'est pas possible, c'est plutôt que l'inférence de type n'est pas toujours capable de le faire tout seul et qu'il faut l'"aider" avec :>...


oui bon, ça va j'ai confondu tripo
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

72

&#10096;13:44&#10097; benjamin@bookeldor-main:~/merdier&#10095;ocaml
        Objective Caml version 3.08.3

# class mother =
object(o)
 method m () =
  print_string "mother\n"
end;;
        class mother : object method m : unit -> unit end

# class daughter =
object(o)
 inherit mother as mom
 method m2 () =
  print_string "daughter\n"
end;;
          class daughter : object method m : unit -> unit method m2 : unit -> unit end

# let plop () =
   let c = new mother
   and d = new daughter
   in
   let e = (d :> mother)
   in
     c#m ();
     d#m2 ();
     (e :> daughter)#m2 ()
  ;;
This expression cannot be coerced to type
  daughter = < m : unit -> unit; m2 : unit -> unit >;
it has type mother but is here used with type #daughter
Only the second object type has a method m2

# let plop_qui_marche () =
 let c = new mother
 and d = new daughter
 in
 let e = (d :> mother)
 in
   c#m ();
   d#m2 ();
   ((Obj.magic e) : daughter)#m2 ()
;;
                  val plop_qui_marche : unit -> unit = <fun>

# plop_qui_marche ();;
mother
daughter
daughter
- : unit = ()
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

73

Oui, c'est un upcast, disons que contrairement à tout le reste, c'est compréhensible que ça ne marche pas smile (ça peut être sympa dans certaines circonstances, mais garantir une certaine opacité du style "si cette fonction prend en argument une mother, alors elle va considérer son argument uniquement comme une mother" n'est pas sans avantages non plus... un peu comme la différence entre le passage par valeur et le passage par référence : passer une variable par valeur, ça empêche de la modifier, mais du côté de l'appelant tu as la garantie que ta variable ne sera pas modifiée après l'appel de la fonction...)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

74

oui c'est sympa, et d'ailleurs Obj.magic n'est pas là pour rien smile
mais bien souvent, quand on est obligé d'utiliser ça, ça veut dire qu'on a pas trop pensé dans le style fonctionnel ocaml tongue
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

75

un truc sympa ça serait de faire un

match (instanceof o) with
   mother -> o#m
| daughter -> o#m2
;;


malheuresement le typage n'étant pas propagé à l'execution, un opérateur instanceof ne peut pas exister en ocaml...

edit: code plus clair
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

76

BookeldOr :
oui c'est sympa, et d'ailleurs Obj.magic n'est pas là pour rien smile

erf... si ! sick couic

BookeldOr
: un truc sympa ça serait de faire un <upcast>

Ben non, comme je l'ai dit à mon avis c'est "by design" que c'est comme ça...
Par exemple ça te garantit que si tu fais une classe "rle_string" qui se comporte comme la classe "string" mais avec un encodage interne différent (par exemple RLE), alors une chaîne RLE donnée :>-ée en string et passée à une fonction se comportera *toujours* comme la même chaîne recréée "from scratch" mais avec l'encodage classique...
(alors que si les upcasts étaient possibles, il se pourrait qu'il y ait des différences de comportement pas forcément facile à détecter entre les deux...)

Pour reprender mon analogie avec le passage de paramètre par référence, ça ne coûterait pas grand chose non plus de faire en sorte que les paramètres soient tjs passés par référence, mais ça pourrait introduire sournoisement des bugs si par hasard un paramètre était modifié sans qu'on s'en rende compte... (i.e. comprendre un bout de code donné juste en le lisant est nettement plus délicat parce que n'importe quelle partie du code peut interagir avec n'importe quelle autre) Du coup ils ont volontairement fait en sorte qu'au moins par défaut, il n'y ait pas de passage par référence -- ça serait peut-être facile à rajouter, mais ils n'en ont pas envie.


PS : http://www.google.fr/search?q=ocaml+class -> argl, on est les deuxièmes eeek

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

77

Pollux :
Ben non, comme je l'ai dit à mon avis c'est "by design" que c'est comme ça...

de toutes façons, comme j'ai dit, actuellement ça n'est pas possible facilement

et puis, pour expliciter que la fonction traite les classes de manière défférente, on pourrait imaginer d'écrire son type en mettant en évidence la disjonction, par exemple
(mother | daughter) -> ()
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

78

au fait,
vous avez essayé de typer le prog que j'ai posté un peu plus haut ?
c'est assez marrant tongue
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

79

BookeldOr
:
Pollux :
Ben non, comme je l'ai dit à mon avis c'est "by design" que c'est comme ça...
de toutes façons, comme j'ai dit, actuellement ça n'est pas possible facilement

Oui, et "comme j'ai dit" c'est volontaire que ça ne soit pas possible ^^
et puis, pour expliciter que la fonction traite les classes de manière défférente, on pourrait imaginer d'écrire son type en mettant en évidence la disjonction, par exemple
(mother | daughter) -> ()

C'est vrai que ça pourrait être sympa d'avoir un type "somme croissante", de la forme A | B | C avec A<B<C, qui pourrait être considéré de façon transparente comme un #A dans tous les cas, puis par pattern-matching pourrait être séparé en #B / A (ou en #C / B) smile

Parce que là les alternatives c'est :
- représenter ça comme une somme disjointe normale, mais c'est un peu pénible pour utiliser le plus grand sous-type commun (ce qui risque d'être pourtant l'utilisation la plus fréquente)
- représenter ça comme le plus grand sous-type commun, avec un "daughter option" en plus pour les opérations spécifiques aux daughter (mais c'est un peu crade, par exemple ça ne fournit aucune garantie que le daughter serait, s'il est présent, physiquement égal au mother)

BookeldOr :
au fait,
vous avez essayé de typer le prog que j'ai posté un peu plus haut ?
c'est assez marrant tongue

./75 ? confus

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

80

Pollux
:
BookeldOr
:
Pollux :
Ben non, comme je l'ai dit à mon avis c'est "by design" que c'est comme ça...
de toutes façons, comme j'ai dit, actuellement ça n'est pas possible facilement

Oui, et "comme j'ai dit" c'est volontaire que ça ne soit pas possible ^^
et puis, pour expliciter que la fonction traite les classes de manière défférente, on pourrait imaginer d'écrire son type en mettant en évidence la disjonction, par exemple
(mother | daughter) -> ()

C'est vrai que ça pourrait être sympa d'avoir un type "somme croissante", de la forme A | B | C avec A<B<C, qui pourrait être considéré de façon transparente comme un #A dans tous les cas, puis par pattern-matching pourrait être séparé en #B / A (ou en #C / B) smile

oui

Parce que là les alternatives c'est :
- représenter ça comme une somme disjointe normale, mais c'est un peu pénible pour utiliser le plus grand sous-type commun (ce qui risque d'être pourtant l'utilisation la plus fréquente)
- représenter ça comme le plus grand sous-type commun, avec un "daughter option" en plus pour les opérations spécifiques aux daughter (mais c'est un peu crade, par exemple ça ne fournit aucune garantie que le daughter serait, s'il est présent, physiquement égal au mother)

pour vérifier ça, un daughter ref option, et on peut vérifier si c'est bien le meme paramètre que le premier avec l'opé ==
mais c'est encore plus lourd

BookeldOr :
au fait,
vous avez essayé de typer le prog que j'ai posté un peu plus haut ?
c'est assez marrant tongue

./75 ? confus


let p x y = fun z -> z x y ;;

let q () = 
  let x1 = fun x -> p x x in 
  let x2 = fun z -> x1 (x1 z) in 
  let x3 = fun z -> x2 (x2 z) in 
  let x4 = fun z -> x3 (x3 z) in 
  let x5 = fun z -> x4 ( x4 z) in 
    x5 (fun z -> z);;

(facile à comprendre que le type généré croit très vite, avec un x6 c'est encore plus long, etc... tongue
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

81

BookeldOr :
pour vérifier ça, un daughter ref option, et on peut vérifier si c'est bien le meme paramètre que le premier avec l'opé == mais c'est encore plus lourd

Ah non je ne parle pas de le vérifier dynamiquement (d'ailleurs pas besoin de référence pour ça, == suffit), je parle d'être sûr que c'est le cas statiquement...

let p x y = fun z -> z x y ;;

let q () = 
  let x1 = fun x -> p x x in 
  let x2 = fun z -> x1 (x1 z) in 
  let x3 = fun z -> x2 (x2 z) in 
  let x4 = fun z -> x3 (x3 z) in 
  let x5 = fun z -> x4 ( x4 z) in 
    x5 (fun z -> z);;

(facile à comprendre que le type généré croit très vite, avec un x6 c'est encore plus long, etc... tongue

Oui je connaissais ^^

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

82

./59 > ben d'après ce qu'on m'a dit le sous-typage implicite est "incompatible" avec l'inférence de type à la caml (par unification), j'ai pas les détails mais il s'agit d'un problème algorithmique d'après ce que j'ai compris...
Moumou :
Sally > Ben en fait je n'ai jamais fait d'OO à la caml, mais je pensais que ça marchait un peu pareil que java, non ? Ie quand on déclare une classe on déclare qu'elle hérite d'une autre, et dans ce cas toute fonction qui prend en argument la classe mère peut prendre la classe fille.
Non ça n'a absolument aucun rapport avec java. Une fois qu'un objet est défini on oublie complètement avec quelle classe on l'a défini, une classe peut hériter de plusieurs classes différentes, et si tu veux que deux objets de deux classes différentes qui ont les mêmes méthodes soient considérés comme de types incompatibles (comme en java) il faut masquer les types concrets dans la signature du module (mais dans ce cas autant ne pas utiliser des objets...)
En fait d'un certain point de vue les classes java sont presque plus proches des *modules* caml que des classes caml grin

./69on : chaine -> caractere -> chaine list = <fun>
 > oui pour que ça passe il faut aller jusqu'à # let fonction = (paire_vers_liste : chaine -> chaine -> chaine list :> chaine -> caractere -> chaine list);;    
val foncti
sinon il n'arrive pas à voir que la coercition est correcte cheeky

BookeldOr > Obj.magic n'est pas faite pour être utilisée dans du code utilisateur hein :P (ce n'est pas un oubli si elle n'est pas documentée ^^). C'est fait juste pour le compilateur et à la rigueur l'interfaçage avec du code C externe...
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

83

tiens, on était là tous les trois ce soir, on aurait du parler de caml trigic!
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

84

Ben il manquait moumou pour poser les questions grin
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#