π
<-
Chat plein-écran
[^]

Classes custom

Pour TI-Nspire OS 3.0 ou ultérieur.

Classes custom

Message non lude DarkFire » 24 Mar 2015, 20:50

Bonjour! :)

J'ai récemment mis au point un code pour créer des classes en Lua, que je pense meilleur que celui de base, puisque il gére l'héritage multiple et tout ça en peu de ligne de code! ;)
J'aimerai savoir ce que vous en pensez, et j'essayerai de voir si je peux optimiser le code où ajouter des fonctionnalité plus complexe.
Code: Tout sélectionner
local setmetatable = setmetatable
local unpack = unpack
local pairs = pairs
local ipairs = ipairs
local string_match = string.match

do
   -- __call
   local function __call(self,...)
      local ins = setmetatable( {}, getmetatable(self) )

      for k,v in pairs(self) do
         if k ~= "__call" then
            ins[k] = v
         end
      end

      if ins.init then ins:init(...) end
      return ins
   end

   -- __is
   function is(o,c)
      if getmetatable(o) == getmetatable(c) then
         return true
      else
         for i,v in ipairs(o.__parents) do
            if v:is(c) then
               return true
            end
         end
      end
      return false
   end
   
   -- __super
   function super(ins, superclass)
      if ins == superclass then
         return superclass
      else
         return ins.__parents[1]
      end
   end
   
   -- Class
   function Class(...)
      -- create the new class table
      local c = {__parents={...}, is=is, super=super, __call=__call}
      -- inherit all
      for i=1,#c.__parents do
         for k,v in pairs(c.__parents[i]) do
            if not c[k] then
               c[k] = v  -- copy the parent table content into the new class
            end
         end
      end

      return setmetatable(c,c)
   end
end -- do block


Et si la fonction class de base vous suffit sur la Ti-Nspire, elle n'existe pas sur PC, donc elle reste toujours utile! :#top#:
Dernière édition par DarkFire le 16 Avr 2015, 23:21, édité 3 fois.
Avatar de l’utilisateur
DarkFire
Niveau 3: MH (Membre Habitué)
Niveau 3: MH (Membre Habitué)
Prochain niv.: 28%
 
Messages: 14
Inscription: 14 Mar 2015, 23:28
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: 1ere S (SI)

Re: Classes custom

Message non lude Adriweb » 24 Mar 2015, 20:58

C'est une bien vieille idée de vouloir améliorer le système de classe existant :P Ca a été fait (cf. Jim Bauwens), mais peu utilisé il me semble.
Enfin bref, ça peut être utile, quand on en a besoin, certes :)

Quelques trucs:
- Tu ne copies pas les metatables des parents - c'est voulu ?
- Le problème avec l'héritage multiple, c'est si plusieurs méthodes sont valables (même signatures) - laquelle appeler ?
- Je vais demander à Jim de faire un tour sur ce topic :P

Pour info, le code de class([parent]) de TI (source Wiki Inspired-Lua):
Show/Hide spoilerAfficher/Masquer le spoiler
Code: Tout sélectionner
class = function(prototype)
local derived={}
   if prototype then
      function derived.__index(t,key)
         return rawget(derived,key) or prototype[key]
      end
   else
      function derived.__index(t,key)
         return rawget(derived,key)
      end
   end
   function derived.__call(proto,...)
      local instance={}
      setmetatable(instance,proto)
      local init=instance.init
      if init then
         init(instance,...)
      end
      return instance
   end
   setmetatable(derived,derived)
   return derived
end
Image

MyCalcs: Help the community's calculator documentations by filling out your calculators info!
MyCalcs: Aidez la communauté à documenter les calculatrices en donnant des infos sur vos calculatrices !
Inspired-Lua.org: All about TI-Nspire Lua programming (tutorials, wiki/docs...)
Avatar de l’utilisateur
AdriwebAdmin
Niveau 16: CC2 (Commandeur des Calculatrices)
Niveau 16: CC2 (Commandeur des Calculatrices)
Prochain niv.: 80.2%
 
Messages: 14616
Images: 1218
Inscription: 01 Juin 2007, 00:00
Localisation: France
Genre: Homme
Calculatrice(s):
MyCalcs profile
Twitter/X: adriweb
GitHub: adriweb

Re: Classes custom

Message non lude DarkFire » 24 Mar 2015, 21:30

Adriweb a écrit:- Tu ne copies pas les metatables des parents - c'est voulu ?

Hmm... Tu me fais réfléchir... Parce que le seul regret sur cette version, c'est que je ne peux pas tester si une classe a hérité d'une autre...
Adriweb a écrit:- Le problème avec l'héritage multiple, c'est si plusieurs méthodes sont valables (même signatures) - laquelle appeler ?

C'est vrai que là, on ne peut qu'appeller la dernière méthode enregistrée... Pour gérer ça, il faudrait faire un truc avec __index et __newindex. Je vais y réfléchir. (En fait j'avais déjà bossé sur les classes en Lua pour PC il y a un moment, et je suis parvenu à un système d'héritage multiple avec l'accès et la création interdite aux attributs hors des méthodes,etc...
Mais c'était plutôt long et j'ai décidé de le réecrire en plus court sans toute ces limitations... Voila le code:
Show/Hide spoilerAfficher/Masquer le spoiler
Code: Tout sélectionner
Class = {}
function Class:new(...)
   -- * Class method "new", to create new Class * --
   local mt = {__call=self.__call}
   mt.__metatable = "private stuff"
   mt.__newindex = function(t, k, v)
      if type(v) == "function" then
         t.__met[k] = v
      end
   end
   local class = setmetatable({__met={},__atr={},__a=false}, mt)
   -- inherit
   local t = unpack{{...}}
   for c in ipairs(t) do
      for i in pairs(t[c]) do
         for k, v in pairs(t[c].__met) do
            class.__met[k] = v
         end
         for k, v in pairs(t[c].__atr) do
            class.__atr[k] = v
         end
      end
   end
   -- return the class table
   return class
end

function Class:__call(...)
   -- * Class method "__call", to create instance * --
   local ins = {__met={},__atr={},__a=false}
   for k, atr in pairs(self.__atr) do
      ins.__atr[k] = atr
   end
   for k, met in pairs(self.__met) do
      ins.__met[k] = function(...)
         local old__a = ins.__a
         ins.__a = true
         local f = met(...)
         ins.__a = old__a
         return f
      end
   end
   local mt = {__metatable="private stuff"}
   mt.__index = function(t, k)
      if t.__met[k] then
         return t.__met[k]
      elseif t.__a and t.__atr[k] then
         return t.__atr[k]
      end
   end
   mt.__newindex = function(t, k, v)
      if type(v) == "function" then
         t.__met[k] = v
      elseif type(v) ~= "function" then
         t.__atr[k] = v
      end
   end

   setmetatable(ins, mt)
   ins:__init(...)
   ins.__met.__init = nil
   return ins
end


Merci pour la réponse rapide! :D

EDIT: Je pense avoir trouvé la solution pour les signatures identique, le truc serait de faire comme les fonctions memoize: on enregistre les arguments. Sauf que là on enregistre le type des arguments et non pas la valeur.
Avatar de l’utilisateur
DarkFire
Niveau 3: MH (Membre Habitué)
Niveau 3: MH (Membre Habitué)
Prochain niv.: 28%
 
Messages: 14
Inscription: 14 Mar 2015, 23:28
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: 1ere S (SI)

Re: Classes custom

Message non lude technolapin » 25 Mar 2015, 21:40

Je sais pas vraiment ce que c'est les classes héritées ou pas (parce que il n'y en a pas en lua nspire de base ou alors j'en ai jamais eu besoin), mais j'ai pas pu résister à canger des détails :p :
Code: Tout sélectionner
do
   local function __call(ins,...)
     -- ins (que tu a appellé self) est déjà une instance parce que c'est comme ça en lua
     pcall(ins:init(...)) -- je sais pas si c'est vraiment mieux, mais j'aime bien les pcall, c'est pratique (ne retourne rien si ça fait une erreur et ignore cette erreur)
      return ins
   end

   function Class(...)
      -- create the new class table
      local c = {__call=__call}

      local parents = {...}
      -- inherit all
      for a, b in pair (parents) do -- + efficace ou au pire je suis juste un maniaque des pairs
         for k,v in pairs(b) do
            c[k] = v  -- copy the parent table content into the new class
         end
      end

      return setmetatable(c,c)
   end
end


Voilà, ça sert à rien de faire ces changements à part pour simplifier un peu et gagner 0.0001% de performance environ.
Votez Kasane Teto 2017
Avatar de l’utilisateur
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Prochain niv.: 97.8%
 
Messages: 514
Images: 25
Inscription: 31 Déc 2012, 10:48
Localisation: Chez moi
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: Chui en vacance ducon

Re: Classes custom

Message non lude DarkFire » 26 Mar 2015, 19:57

A non désolé, mais la fonction __call n'est pas valide du tout: j'ai besoin de renvoyer une copie de self, pas de self lui même...
pour ce qui est des performances, un simple test booléen sera toujours plus rapide qu'une fonction et c'est pareil pour la boucle for (car pairs est une fonction). Mais sinon, c'est simpa de m'aider à optimiser mon code! ;)
( Voir https://springrts.com/wiki/Lua_Performance )

Sinon j'ai modifié mon code, maintenant il supporte:
- Les tests pour savoir si un objet est de telle ou telle classe qui est facilement accesible via une comparaison classique ou la fonction is(o, c)
- Une fonction super qui retourne soit le premier parent connu de la classe, soit l'un des parent donné en argument qui s'écrit super(ins,[superclass)
- Et très important: la suppression de la métaméthode __call lors de la création de l'objet!
Avatar de l’utilisateur
DarkFire
Niveau 3: MH (Membre Habitué)
Niveau 3: MH (Membre Habitué)
Prochain niv.: 28%
 
Messages: 14
Inscription: 14 Mar 2015, 23:28
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: 1ere S (SI)

Re: Classes custom

Message non lude technolapin » 27 Mar 2015, 12:26

Ah non, faire un pcall est plus rapide que de vérifier que la fonction est exécutable puis l’exécuter.
Code: Tout sélectionner
local function __call(ins,...)
         pcall(ins:init(...))
         return ins
       end

revient à la même chose que
Code: Tout sélectionner
local function __call(self,...)
         local ins = unpack({self})
         if ins.init then ins:init(...) end
         ins.__call = nil
         return ins
       end

mais sans le test, sans les problèmes, en plus court et plus rapide.
Votez Kasane Teto 2017
Avatar de l’utilisateur
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Prochain niv.: 97.8%
 
Messages: 514
Images: 25
Inscription: 31 Déc 2012, 10:48
Localisation: Chez moi
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: Chui en vacance ducon

Re: Classes custom

Message non lude DarkFire » 27 Mar 2015, 13:54

Bon d'accord, mais pcall ou pas, là n'est pas le problème: je le répéte, mais, j'ai absolument besoin d'une copie de la table d'origine!
En programmation orientée objet, une classe est un peu comme le plan de construction d'un objet.
Avec mon code, on crée une classe comme ça:
Show/Hide spoilerAfficher/Masquer le spoiler
Code: Tout sélectionner
local Car = Class()
function Car:init(max_speed)
    self.max_speed = max_speed
    self.speed = 0
    self.started = false
end

function Car:start()
    self.started = true
end

Et on l'instancie comme ça:
Show/Hide spoilerAfficher/Masquer le spoiler
Code: Tout sélectionner
local voiture1 = Car(120)
local voiture2 = Car(130)
local voiture3 = car(140)

Comme tu peux le remarquer, il est possible de créer plusieurs instance de "Car", donc il faut en créer des copies.
En plus, la classe n'est censé contenir que des méthodes, et pas autre chose.
Les autres type de variables sont crée par la fonction "init".

Alors que le code que tu me propose ne copie aucune table... Donc lorsque tu appelle __call tu retourne la classe elle même.
C'est comme si une classe était un plan de construction d'une maison, et que lorsque tu envoie des ouvriers construire la maison, à la place ils modifient le plan de construction original...

Si ce n'est pas clair, je t'invite à te renseigner sur la programmation orientée objet (POO ou encore OOP pour les intimes) ;)
Avatar de l’utilisateur
DarkFire
Niveau 3: MH (Membre Habitué)
Niveau 3: MH (Membre Habitué)
Prochain niv.: 28%
 
Messages: 14
Inscription: 14 Mar 2015, 23:28
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: 1ere S (SI)

Re: Classes custom

Message non lude technolapin » 27 Mar 2015, 19:16

Oui mais c'est déjà une copie.
Par exemple, dans ce code, a ne varie pas:
Code: Tout sélectionner
local a = "a"
local function lol (var) var = 1 end
print a
lol(a)
print a

En lua, les arguments renvoient une copie de la variable localisée dans la fonction et non pas la variable originale, la modifier ne change pas la variable originelle.
Votez Kasane Teto 2017
Avatar de l’utilisateur
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Prochain niv.: 97.8%
 
Messages: 514
Images: 25
Inscription: 31 Déc 2012, 10:48
Localisation: Chez moi
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: Chui en vacance ducon

Re: Classes custom

Message non lude Levak » 27 Mar 2015, 19:20

technolapin a écrit:Oui mais c'est déjà une copie.
Par exemple, dans ce code, a ne varie pas:
Code: Tout sélectionner
local a = "a"
local function lol (var) var = 1 end
print a
lol(a)
print a

En lua, les arguments renvoient une copie de la variable localisée dans la fonction et non pas la variable originale, la modifier ne change pas la variable originelle.


Sauf si c'est un tableau.
Avatar de l’utilisateur
LevakAdmin
Niveau 14: CI (Calculateur de l'Infini)
Niveau 14: CI (Calculateur de l'Infini)
Prochain niv.: 98.9%
 
Messages: 6414
Images: 22
Inscription: 27 Nov 2008, 00:00
Localisation: 0x1AACC355
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: BAC+5: Epita (ING3)

Re: Classes custom

Message non lude Adriweb » 27 Mar 2015, 19:25

Levak a écrit:
technolapin a écrit:Oui mais c'est déjà une copie.
Par exemple, dans ce code, a ne varie pas:
Code: Tout sélectionner
local a = "a"
local function lol (var) var = 1 end
print a
lol(a)
print a

En lua, les arguments renvoient une copie de la variable localisée dans la fonction et non pas la variable originale, la modifier ne change pas la variable originelle.


Sauf si c'est un tableau.


(les table en Lua étant purement des pointeurs, d'où l'intérêt de se faire des helpers du genre copyTable et deepCopy)
Image

MyCalcs: Help the community's calculator documentations by filling out your calculators info!
MyCalcs: Aidez la communauté à documenter les calculatrices en donnant des infos sur vos calculatrices !
Inspired-Lua.org: All about TI-Nspire Lua programming (tutorials, wiki/docs...)
Avatar de l’utilisateur
AdriwebAdmin
Niveau 16: CC2 (Commandeur des Calculatrices)
Niveau 16: CC2 (Commandeur des Calculatrices)
Prochain niv.: 80.2%
 
Messages: 14616
Images: 1218
Inscription: 01 Juin 2007, 00:00
Localisation: France
Genre: Homme
Calculatrice(s):
MyCalcs profile
Twitter/X: adriweb
GitHub: adriweb

Suivante

Retourner vers Nspire-Lua

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 15 invités

-
Rechercher
-
Social TI-Planet
-
Sujets à la une
Comparaisons des meilleurs prix pour acheter sa calculatrice !
Aidez la communauté à documenter les révisions matérielles en listant vos calculatrices graphiques !
Phi NumWorks jailbreak
123
-
Faire un don / Premium
Pour plus de concours, de lots, de tests, nous aider à payer le serveur et les domaines...
Faire un don
Découvrez les avantages d'un compte donateur !
JoinRejoignez the donors and/or premium!les donateurs et/ou premium !


Partenaires et pub
Notre partenaire Jarrety Calculatrices à acheter chez Calcuso
-
Stats.
1376 utilisateurs:
>1320 invités
>51 membres
>5 robots
Record simultané (sur 6 mois):
6892 utilisateurs (le 07/06/2017)
-
Autres sites intéressants
Texas Instruments Education
Global | France
 (English / Français)
Banque de programmes TI
ticalc.org
 (English)
La communauté TI-82
tout82.free.fr
 (Français)