nitlang / nit

Nit language
http://nitlanguage.org
Apache License 2.0
242 stars 67 forks source link

spec: Sous-typage avec des types virtuels #298

Open jpages opened 10 years ago

jpages commented 10 years ago

Avec la portion de code suivante :

class A
    type T : Truc

    fun newInstance : T
    do
        var truc = new Truc
        return truc
    end
end

On définit une classe A avec un type virtuel borné par Truc. Dans la méthode newInstance on veut retourner une instance de T.

La borne du type virtuel nous dit que T <: Truc, mais pas que Truc <: T (enfin je crois).

Est-ce que c'est normal ? Et est-ce qu'il faut comprendre T : Truc comme une borne ou alors comme T = Truc (type final fixé). Si c'est une borne, alors dans mon exemple, newInstance devrait lever une erreur et sinon ça me paraît normal.

Morriar commented 10 years ago

Salut Julien.

J'aurais tendance à dire qu'il s'agit plus d'un type final fixé selon ta définition.

Par contre. Ce type n'est pas tant "fixé" car il est possible de le redéfinir de manière covariante dans les sous classes.

class A
      type FOO: Object
end

class B super A
      redef type FOO: Int
end

Le 3 mars 2014 04:11, "jpages" notifications@github.com a écrit :

Avec la portion de code suivante :

class A type T : Truc

fun newInstance : T
do
    var truc = new Truc
    return truc
endend

On définit une classe A avec un type virtuel borné par Truc. Dans la méthode newInstance on veut retourner une instance de T.

La borne du type virtuel nous dit que T <: Truc, mais pas que Truc <: T (enfin je crois).

Est-ce que c'est normal ? Et est-ce qu'il faut comprendre T : Truc comme une borne ou alors comme T = Truc (type final fixé). Si c'est une borne, alors dans mon exemple, newInstance devrait lever une erreur et sinon ça me paraît normal.

Reply to this email directly or view it on GitHubhttps://github.com/privat/nit/issues/298 .

privat commented 10 years ago

« Est-ce c'est normal ? » Ca dépend de ta définition de normal :)

Dans le système de type de Nit, Truc n'est pas sous-type de T. C'est le comportement normalement attendu pour qui suit des cours de prog objet avancée, car non sur (cf le cas de la redéfinition de T). Notons que si T était fixé ; T et Truc deviennent équivalents; donc trivialement sous-type.

Maintenant, pourquoi ce comportement ? Plusieurs raisons dont principalement flemme, compatibilité avec du vieux code et prévision du futur.

En fait, nitg sait que c'est pas sous-type. mais le laisse passer explicitement : cf check_subtype dans typing.nit. le commentaire indique workarround to the current unsafe typing policy. To remove once fixed virtual types exists.

Ensuite, les moteurs savent que certains trucs sont pas sur et ajoutent un cast explicite dans ces cas là. Ils l'appellent autocast dans la terminologie des moteurs.

Le comportement est vérifié dans tests/base_autocast.nit L'option --no-check-autocast désactive ces tests (pour mesurer leur cout par exemple) L'option --typing-test-metrics permet aussi de les compter (statiquement et dynamiquement, c'est la ligne auto) ; dans nitg il y a actuelle 27 autocast dans le code (0.5%), mais ils comptent pour un total de 27M cast au runtime (3.6%). j'imagine que la plupart sont en fait dans kernel.nit

Ainsi, au final dans ton exemple original, Nit rajoute un cast implicite, donc d'une certaine façon c'est traité comme une sorte de covariance non sure :

class A
    type T : Truc

    fun newInstance : T
    do
        var truc = (new Truc).as(T) # ajout cast implicite
        return truc
    end
end

Et pour le futur ? Ben, ces cast implicites sont nul et on devrait plutot lever une erreur statique pour que le programmeur prennent la responsabilité (et 27 cas dans nitg n'est pas impressionnant non plus, donc on peut pas vraiment parler d'une augmentation monstruseuse de verbosité)

Malheureusement ces 27 cas sont sans doute des cas légitime de types virtuels fixés qui n'attendent que ça pour devenit légaux. Ce serait idiot de mettre 27 cast explicites pour les virer a nouveau une fois que le fixage des types virtuels est en place.

Donc, comme plusieurs trucs de Nit, le machin est dans un état ni-fait-ni-a-faire et plutôt que d'ajouter un pansement, on attend qu'un volontaire ajoute le fixage des types virtuels une bonne fois pour toute.

Morriar commented 10 years ago

En fait dans l'example de Jean, le cast est fait sur le return et non le new:

class A
    type T : Truc

    fun newInstance : T do
        var truc = new Truc
        return truc.as(T) # ajout cast implicite
    end
end
jpages commented 10 years ago

Ok d'accord je comprends.

J'essayerai de regarder à l'occasion voir si c'est pas trop compliqué à implémenter.

privat commented 9 years ago

Après analyse et discussion il semblerait qu'il n'y ait pas de solution magique d'éviter un cast, même avec les types virtuels fixés.

Je vais faire des analyses pour compter les cas d'autocasts et il faudra décider si on garde les auto-casts implicite ou si on dois les rendre explicites.