Forum Programmation.ruby Pointeur de fonction ?

Posté par .
Tags : aucun
0
24
avr.
2009
Bonjour,

j'ai un script relativement simple, qui en fonction d'un paramètre utilisateur va appliquer telle ou telle mesure.

Les mesures s'appliquent sur les mêmes valeurs, mais ne les prennent pas en compte de la même façon. Je voudrais faire un code propre qui associe la mesure choisie par l'utilisateur (par exemple "mi" ou "log") à un identificateur (par exemple "my_measure") pour ensuite appeler de façon transparente "my_measure(a,b,c,d,n)".

En perl, il me semble que ça s'appelle un pointeur de fonction. Quelque part dans le code on aura :
$my_measure = \&mi ;
ou
$my_measure = \&log ;
en fonction du choix de l'utilisateur (avec un case, mais probablement avec un truc super gruik parce que c'est du perl).
puis
&$my_measure(a,b,c,d,n)

Je n'arrive pas à faire la même chose en ruby. J'ai trouvé des pistes (à coup de Proc.new) mais j'avoue ne rien y comprendre, et que je trouve ça hardcore pour le simple petit problème que j'ai (du coup je me dis que les réponses ne correspondent pas à ma question).

Cher forum, aurais-tu une idée ?
  • # .call

    Posté par (page perso) . Évalué à 2.

    Si j'ai bien compris ta question, ce qui n'est pas certain, ce que tu recherches c'est "ma_fonction.call"


    def ma_fonction()
    blablabla # je ne sais toujours pas faire les indentations entre les balises < code >
    end

    ma_fonction.call

    • [^] # Re: .call

      Posté par . Évalué à 1.

      Je ne suis pas sûr d'avoir compris ta réponse :)

      J'ai plusieurs fonctions (des exemples jouets ici) :

      def mi(a,b,c,d)
      return a*b*c*d
      end

      def log(a,b,c,d)
      return a/b/c/d
      end

      J'ai un paramètre, "mes" et je fais

      case mes
      when "mi"
      my_function = mi # mais ça marche pas comme ça
      when "log"
      my_function = log # mais ça marche pas comme ça
      end

      et je voudrais qu'un appel à "my_function(a,b,c,d)" appelle log(a,b,c,d) ou mi(a,b,c,d) en fonction du choix du case.

      J'ai trouvé une solution qui me paraît un peu gruik.

      class MesMesures
      def mi(a,b,c,d)
      ...
      end # mi

      def log(a,b,c,d)
      ...
      end # log
      end # class MesMesures

      [...]

      all_func = MesMesures.new
      case mes
      when "mi"
      ma_fonction = all_func.method( :mi )
      when "log"
      ma_fonction = all_func.method( :log )
      end
      ...
      ma_fonction.call(a,b,c,d) # fonctionne !
      • [^] # A corriger

        Posté par (page perso) . Évalué à 2.

        Avec une variable, je n'ai plus Ruby dans les pattes, mais c'est quelque chose du genre: @ma_variable.call

        Sinon: http://www.ruby-doc.org/docs/ProgrammingRuby/html/ospace.htm(...)
      • [^] # on est bien vendredi

        Posté par . Évalué à 3.


        when "mi"
        my_function = mi # mais ça marche pas comme ça


        en python, ca marche bien comme ca :) ---> []
        • [^] # Re: on est bien vendredi

          Posté par (page perso) . Évalué à 2.

          Trop long à taper. En assembleur il suffit de faire:

          call eax

          1 instruction, 7 caractères. Quelqu'un a plus court ? :-)
      • [^] # Re: .call

        Posté par . Évalué à 1.

        Dans le même esprit mais en moins goret:

        class Functions
        def self.foo(a, b, c)
        end

        def self.bar(a, b, c)
        end
        end

        func_name = "bar"

        if Functions.respond_to? func_name
        Functions.method(func_name).call('a', 'b', 'c')
        end
        • [^] # Re: .call

          Posté par . Évalué à 4.

          Mais c'est quoi ce thread : il n'y a pas de first class function en ruby ? C'est une blague ?

          Je dis ça parce que je fais du python, et qu'on me vante souvent ruby comme un langage encore mieux, blah blah. Si on n'est pas capable de résoudre sont problème simplement, il y a vraiment un gros problème.

          Solution en python, sans classe ni trop de bordel :


          def mi(a, b, c, d):
          return a*b*c*d

          def log(a, b, c, d):
          return a/b/c/d

          Puis :

          if mes == "mi":
          ma_fonction = mi
          elif mes == "log":
          ma_fonction = log

          Voire :

          ma_fonction = locals()[mes]

          (ok, l'utilisation de locals() est crade)

          Et on peut ainsi utiliser :

          ma_fonction(1,2,3,4)

          Tout simplement.

          Donc s'il y a des spécialistes de ruby dans le coin, vous pouvez me dire s'il n'y a vraiment pas de first-class function en ruby ? Ou alors justement c'est qu'il n'y a aucun spécialiste ruby sur ce thread ?

          (ne le prenez pas méchamment, c'est juste que j'hallucine grave sur cette lacune si c'en est vraiment une)
          • [^] # Re: .call

            Posté par . Évalué à 4.

            En ruby désigner une fonction reviens a l'appeler, tu ne peut donc pas passer directement une fonction comme tu le ferait en python en ométant les parenthèses, pour la simple et bonne raison que les parenthèses sont optionnelles.

            Pour obtenir le même effet il faut utiliser la "buit-in" method, et ensuite pour l'appeler il faut utiliser la méthode call.


            #python
            func = locals()[func_name]
            func(1, 2, 3)

            #ruby
            func = method(func_name)
            func.call(1, 2 , 3)


            Mais cet exemple que ce soit en python ou en ruby est a éviter car si j'ai bien suivi le nom de la fonction viens d'une saisie utilisateur. Il vaut donc mieux isoler les fonctions disponibles dans un espace de nom (une classe) car si par un hasard soudain func_name == 'exit' ben ...
            • [^] # Re: .call

              Posté par . Évalué à 2.

              OK, merci pour ces précisions.
  • # send et method/call

    Posté par . Évalué à 2.

    Je vois deux solutions 'simple' une avec send (on envoie un message à l'objet, c'est la façon smalltalk d'appeler une methode il me semble) :

    my_function="mi"
    send(my_function,1,2,3,4);

    my_function=:log
    send(my_function,1,2,3,4)


    Ou avec method et call cité plus haut :

    my_function = method(:mi)
    my_function.call(1,2,3,4)

    my_function = method("log")
    my_function.call(1,2,3,4)


    Dans les deux cas on peu utiliser une chaine de carractere ou un symbole (:mi ou :log). J'imagine qu'avec un symbole le code doit etre plus performant, cela dit je n'en suis pas sur.

    Comme en ruby la ligne de code "my_function(1,2,3,4)" serais equivalent à "self.send(:my_function,1,2,3,4)" je ne crois pas qu'il existe de solution où l'on puisse appeler "my_function(1,2,3,4)" comme on le ferais avec un pointeur de fonction en C par exemple.

    Cordialement.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.