Polymorphisme et fonctions / méthodes

Fermé
PerlGirafe - 1 janv. 2013 à 13:20
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 - 14 janv. 2013 à 10:21
Bonjour tout le monde, et bonne année 2013, meilleurs voeux :)

Je cherche à définir deux méthodes dans une classe (package) du même nom, qui ont un comportement plus ou moins similaire, mais avec des spécificités. Les méthodes se nomment "Add", ma classe "TestObject".


package TestObject;
...

sub Add {
      my($this, $data) = @_;
      ...
}

sub Add {
      my($this, $data, $position) = @_;
      ...
}


Comme le montre le code, je cherche a appeler deux versions différentes de Add() si j'ai un ou deux arguments.
J'ai fais pas mal de recherche, je n'ai rien trouvé. Donc je viens vous demander votre aide :D
J'ai l'habitude du C++, donc mon raisonnement est certainement influencé par ça... malheureusement :p

2 réponses

[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
10 janv. 2013 à 15:12
Tu ne peux pas créer deux fonctions (méthodes) avec le même nom dans un même espace de nommage (Package définissant ta classe).

Tu as (au moins) deux choix :

1- tu définis une seule méthode Add dans TestObject, qui agit différemment selon le nombre de paramètres passés

2- tu définis un autre objet TestObject::Special, qui hérite de TestObject, et qui définit une méthode Add avec ses spécificités.

Voilà un exemple qui illustre ces deux façons de faire :

#!/usr/bin/perl

package TestObject;

use strict;
use warnings;

sub new {
    my $class = shift;
    my $number = shift;
    my $self = {};
    bless( $self, $class );
    $self->{num} = $number;
    print "Initialized self->{num} = $self->{num}\n";
    return $self;
}

sub Add {
    my $self = shift;
    my $data;
    my $position;

    print "I am a TestObject\n";
    my $param_count = @_;
    if ($param_count == 1) {
        $data =  shift;
        print "Only one parameter was passed\n";
        print "doing something with data = $data\n";
        $self->{num} += $data;
    } elsif ($param_count == 2) {
        $data =  shift;
        $position =  shift;
        print "Two parameters were passed\n";
        print "doing something with data = $data and position = $position\n";
        $self->{num} += $data * $position;
    } else {
        print "Error: wrong number of parameters";
    }
    print "ending Add, the object holds self->{num} = $self->{num}\n\n";
}

package TestObject::Special;

use strict;
use warnings;

@TestObject::Special::ISA = qw(TestObject);

sub Add {
    my $self = shift;

    print "I am a TestObject::Special, Add takes 2 arguments only here\n";
    my $param_count = @_;
    if ($param_count == 2) {
        my $data = shift;
        my $position = shift;
        print "doing something with data = $data and position = $position\n";
        $self->{num} += $data * $position;
    } else {
        print "Error: wrong number of parameters";
    }
    print "ending Add, the object holds self->{num} = $self->{num}\n\n";
}

package main;

use strict;
use warnings;

my $thing1 = TestObject->new(12);
my $thing2 = TestObject->new(12);
my $thing3 = TestObject::Special->new(12);
$thing1->Add(3);
$thing2->Add(3,2);
$thing3->Add(3,2);

Cela produit le résultat suivant :

$ ./PerlGirafe.pl
Initialized self->{num} = 12
Initialized self->{num} = 12
Initialized self->{num} = 12
I am a TestObject
Only one parameter was passed
doing something with data = 3
ending Add, the object holds self->{num} = 15

I am a TestObject
Two parameters were passed
doing something with data = 3 and position = 2
ending Add, the object holds self->{num} = 18

I am a TestObject::Special, Add takes 2 arguments only here
doing something with data = 3 and position = 2
ending Add, the object holds self->{num} = 18

Dal
0
Merci beaucoup pour ta réponse.
C'est dommage que Perl ne permette pas un polymorphisme aussi évolué que le C++. J'espère que ce manque (à mon sens tout du moins) sera comblé dans de futur versions... (au pire, j'ai python, mais bon...)
La première solution est celle que j'avais retenue pour avancer dans mon code, mais je la trouvais un peu "salle". L'idée d'appeler une methode intermediaire me déplait, mais apparemment, je n'ai guère le choix, vu que je veux produire un code simple, sans avoir besoin de créer d'objets dérivés pour deux ou trois méthodes...

En tout cas, merci encore de ta réponse :D
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
14 janv. 2013 à 10:21
Salut PerGirafe,

Je ne suis pas un dieu de l'orienté objet, que j'évite quand je peux.

Mais, je pense que tu décris, c'est la surcharge de fonctions au sein d'une même classe. Pas réellement le polymorphisme.

La surcharge dans un langage comme le C++ ou Java est rendue nécessaire par le fait que ces langages imposent une déclaration rigide des paramètres. La surcharge (overloading) de ces langages permet alors de composer avec cette contrainte, en créant une méthode avec le même nom, mais avec des paramètres différents (en nombre ou en type). Lors de la compilation, le compilateur va déterminer, en fonction des paramètres passés, quelle est la fonction réellement appelée.

Perl est suffisamment flexible pour que cela ne soit pas nécessaire (cf. exemple 1.). Tu peux voir cela comme un manque, ou comme une qualité (avoir à redéfinir une méthode sous prétexte qu'elle peut avoir un argument de plus, alors qu'elle fait par ailleurs presque la même chose, est aussi une contrainte).

Cette page en parle plus en détails : https://www.perl.com/pub/2003/07/22/overloading.html/

Perl supporte en revanche la surcharge d'opérateurs, comme l'indique aussi cette page.

Le polymorphisme, me semble être un concept différent. Il consiste à changer l'implémentation ou les fonctionnalités d'une méthode particulière présente sur différents types en raison d'une base commune, et est intimement lié au concept d'héritage, l'usage d'une classe abstraite, ou une interface. Cela ne se passe d'ailleurs plus au stade de la compilation, mais de l'exécution.

Cela dit, l'un des chantiers de Perl 6 est effectivement d'améliorer la programmation orienté objet, en la simplifiant :

https://en.wikipedia.org/wiki/Perl_6#Object-oriented_programming

Si tu vas faire beaucoup de OOP en Perl, tu aurais intérêt à te pencher sur Moose : https://moose.iinteractive.com/en/ qui est largement utilisé par la communauté Perl et qui anticipe la philosophie de l'OOP dans Perl 6.


Dal
0