• [^] # Re: Critique du langage.

    Posté par . En réponse à la dépêche Le language de programmation ooc sorti en version 0.2. Évalué à 1.

    J'ai pas mal réfléchi à cette question déjà au début de la conception d'ooc, et j'ai décidé de faire un héritage à la Java: une classe parente maximum, et tu implémentes autant d'interfaces que tu veux.

    Pourquoi maintenir la différence entre classe et interface? Parce que dans l'implémentation courante, les casts entre sous-classes et super-classes sont quasiment gratuits, ce sont de bêtes casts C;

    abstract class Parent {
    abstract func call;
    }

    class Child from Parent {
    implement call {
    // blablablah.
    }
    }

    func doThing(Parent p) {
    p.call;
    }

    func main {
    // le fait de passer un Child au lieu d'un Parent
    // n'induit quasiment aucune pénalité
    doThing(new Child);
    }

    puisque les champs et les fonctions, dans leurs structures respectives, sont ordonnés dans l'ordre d'héritage (un enfant a les champs/fonctions de ses parents dans le même ordre, puis les siens, voir l'ABI "standard" ooc dans le language reference guide).

    Dans le cas d'une interface, voila comment je pensais l'implémenter:
    - Une "map" (concrètement un tableau de pointeurs de fonction), donc les clés sont des identifiants qui correspondent a un nom pleinement qualifié d'interface (codés par je ne sais quel algorithme miracle qui prend avantage du fait que seuls les caractères alpha-numériques sont autorisés dans les noms de paquetages), et dont les valeurs sont des pointeurs vers des structures qui contiennent un tableau de pointeurs sur les implémentation par la classe des fonctions de l'interface et ce dans le bon ordre de déclaration.
    En bref, une fois de plus, pour implémenter le polymorphisme j'utilise des structures avec des pointeurs sur fonction qui sont assignés aux bonnes implémentations a l'initialisation, et retournées suivant vers quoi on cast. Retourner le parent est "straight-forward", mais retourner une interface, pas, puisqu'une classe peut potentiellement implémenter un nombre infini d'interfaces et ce dans n'importe quel ordre.

    interface Callable {
    abstract func call;
    }

    // pas de différence de mot-clé entre super-classe/interface. bien? mal? c'est en réflexion.
    class Concrete from Callable {
    implement call {
    // blablablah.
    }
    }

    func doThing(Callable c) {
    c.call;
    }

    func main {
    // le fait de passer un Concrete au lieu d'un Callable
    // implique un cast implicite vers une interface
    doThing(new Concrete);
    }

    En résumé donc; il y aurait une pénalité pour caster vers une interface, mais une fois casté, l'appel de fonctions est aussi peu cher que l'appel de fonctions d'une classe/super-classe directement.

    Note: s'il y a une implémentation évidente, plus simple et plus performante à la fois, je suis tout à fait preneur. Sinon, je pense aller par cette voie.