2017-07-11 3 views
5

Comment sous-classer IO :: Handle? Par exemple, je veux être en mesure de « autoflush » en appelant au ras après chaque say:Comment pourrais-je sous-classer IO :: Handle de Perl 6?

class MyIO is IO::Handle { 
    multi method say(MyIO:D: **@text --> True) { 
     nextsame; 
     $*ERR.say: "Flushing\n"; 
     self.flush; 
     } 
    }; 

Metamodel::Primitives.rebless: $*OUT, MyIO; 
put $*OUT.^name; 

$*OUT.say: "This is standard out"; 

Mais, il semble que MyIO est jamais appelé.

Je me dis que je pourrais envelopper pour dire produire l'effet, mais je suis plus intéressé par la technique des sous-classes simples pour remplacer certains comportements. Mais, cela étant dit, s'il y a plus de moyens Perly que la conception a l'intention d'utiliser.

Alors, quelques questions:

  • Est-ce que Perl 6 soins de actaully que je reblessed il? Comment recherche-t-il les noms de méthodes qui pourraient l'ignorer? Les classes intégrées sont-elles particulièrement résistantes aux techniques OO standard en raison de leur sorcellerie et de leur NQP? Est-ce que Perl 6 décourage le bas niveau avec des poignées, comme la réouverture de $ * OUT sur un descripteur de fichier? (Comme dans Does changing Perl 6's $*OUT change standard output for child processes?)

+0

Un peu de prédiction future: le langage 6.d aura des méthodes spécifiques sur IO :: Handle que vous pouvez remplacer dans vos sous-classes pour affecter * tout * l'écriture/lecture. Les noms de travail actuels sont '.write-internal',' .read-internal', et '.eof-internal' bien que les noms soient encore bikeshedded et specced. Un aperçu de leur utilisation peut être vu dans [impl impl. de IO :: Pipe] (https: // github.com/rakudo/rakudo/blob/58900e7ba8ad31d905968d950bd9066a239320f5/src/noyau/IO/Pipe.pm # L25-L51) –

+2

Notez également que ['nextsame' ne revient pas à l'appelant] (https://rakudo.party/ post/Perl6-mais-Heres-My-Dispatch-So-Callwith-Peut-être). –

+1

si vous exécutez '.perl.say pour $ * OUT.^Find_method (" dites "). Candidats' vous pouvez voir que votre candidat apparaît en effet. Ce n'est pas assez spécifique, c'est-à-dire que les candidats «$ text» gagnent sur votre candidat «** @ args». – timotimo

Répondre

10

Reblessing est sooo :-) de la 90

Pourquoi ne pas utiliser la composition de rôle pour atteindre votre objectif?

role MyWay { 
    method say(|) { 
     note "whee"; 
     nextsame 
    } 
} 
my $*OUT = PROCESS::<$OUT> but MyWay; 
$*OUT.say("foo") # whee\nfoo 

Cela crée essentiellement une nouvelle $*OUT dynamique basée sur l'$*OUT existant, mais avec une nouvelle méthode say mélangée à

Pour répondre à vos questions aussi bien que je peux.

  • reblessing est Considéré comme quelque chose d'interne que vous ne voulez probablement pas faire
  • Beaucoup de classes intégrées sont optimisées pour la vitesse en n'utilisant pas la manière standard de créer des objets. Ce sorta rend difficile de les sous-classer. Dans certains cas, le code spécial revient à la manière standard de créer des objets, rendant ces classes sous-classables après tout (comme Date).
  • En général, je dirais que le bas niveau n'est pas conseillé car il y a encore des refacteurs internes en cours pour accélérer les choses, ce qui pourrait casser votre code si vous jouez trop bas.

Depuis say utilise en interne print, il serait préférable de mélanger réellement dans votre propre méthode print:

role MyWay { 
    method print(|) { 
     note "whee"; 
     nextsame 
    } 
} 
my $*OUT = PROCESS::<$OUT> but MyWay; 
say "foo"; # whee\nfoo 

Cela a l'avantage de ne plus avoir besoin d'appeler say comme méthode, parce que la sous-version de say va chercher le $*OUT modifié dynamiquement.