Perl 5'in işlev prototipleri neden kötü?


116

Başka bir Stack Overflow sorusunda Leon Timmermans şunları söyledi:

Prototip kullanmamanızı tavsiye ederim. Kullanımları var, ancak çoğu durumda değil ve kesinlikle bunda değil.

Bu neden doğru (veya başka türlü) olabilir? Perl işlevlerim için neredeyse her zaman prototipler temin ederim ve daha önce hiç kimsenin bunları kullanmakla ilgili kötü bir şey söylediğini görmedim.


Ben de merak ediyorum. Bunları kullanmadığım tek zaman, değişken sayıda argümanla aradığım zamandır.
Paul Tomblin

7
“Zararlı Olarak Görülen Perl Prototipleri” başlıklı makaleyi okumanızı tavsiye edebilir miyim?
tchrist

Yanıtlar:


121

Doğru kullanıldığında prototipler kötü değildir. Zorluk, Perl'in prototiplerinin insanların genellikle bekledikleri şekilde çalışmamasıdır. Diğer programlama dillerinde bir geçmişe sahip kişiler, prototiplerin işlev çağrılarının doğru olup olmadığını, yani doğru sayıda ve türde argümanlara sahip olduklarını kontrol etmek için bir mekanizma sağlamasını bekleme eğilimindedir. Perl'in prototipleri bu görev için pek uygun değil. Kötü olan kötüye kullanım . Perl'in prototiplerinin tek ve çok farklı bir amacı vardır:

Prototipler, yerleşik işlevler gibi davranan işlevleri tanımlamanıza olanak tanır.

  • Parantezler isteğe bağlıdır.
  • Bağlam argümanlara empoze edilir.

Örneğin, şöyle bir işlev tanımlayabilirsiniz:

sub mypush(\@@) { ... }

ve olarak adlandır

mypush @array, 1, 2, 3;

\diziye bir referans almak için yazmaya gerek kalmadan .

Özetle, prototipler kendi sözdizimsel şekerinizi yaratmanıza izin verir. Örneğin Moose çerçevesi, daha tipik bir OO sözdizimini taklit etmek için bunları kullanır.

Bu çok kullanışlıdır, ancak prototipler çok sınırlıdır:

  • Derleme sırasında görünür olmaları gerekir.
  • Baypas edilebilirler.
  • Bağlamın bağımsız değişkenlere yayılması, beklenmeyen davranışlara neden olabilir.
  • Kesin olarak öngörülen formdan başka herhangi bir şey kullanarak işlevleri çağırmayı zorlaştırabilirler.

Tüm kanlı ayrıntılar için perlsub'daki prototiplere bakın .


2
Bu yanıtı kabul ettim çünkü soruyu en iyi yanıtladığına inanıyorum - prototipler özünde kötü değil, sadece onları nasıl kullandığınızdır.
Alnitak



Öyleyse onlar yanlış bir isim mi?
Peter Mortensen

69

Sorun, Perl'in işlev prototiplerinin insanların yaptıklarını düşündüklerini yapmamasıdır. Amaçları, Perl'in yerleşik işlevleri gibi ayrıştırılacak işlevler yazmanıza izin vermektir.

Her şeyden önce, yöntem çağrıları prototipleri tamamen yok sayar. OO programlama yapıyorsanız, yöntemlerinizin hangi prototipine sahip olduğunun önemi yoktur. (Yani herhangi bir prototipi olmamalıdır.)

İkincisi, prototipler kesinlikle uygulanmaz. İle bir alt rutini çağırırsanız &function(...), prototip yok sayılır. Bu yüzden gerçekten herhangi bir güvenlik sağlamazlar.

Üçüncüsü, uzaktaki ürkütücü eylemler. (Özellikle $ilgili parametrenin varsayılan liste bağlamı yerine skaler bağlamda değerlendirilmesine neden olan prototip.)

Özellikle, dizilerden parametrelerin aktarılmasını zorlaştırırlar. Örneğin:

my @array = qw(a b c);

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

sub foo ($;$$) { print "@_\n" }

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

baskılar:

a b c
a b
a b c
3
b
a b c

3 uyarı ile birlikte main::foo() called too early to check prototype(uyarılar etkinleştirilmişse). Sorun, skaler bağlamda değerlendirilen bir dizinin (veya dizi diliminin) dizinin uzunluğunu döndürmesidir.

Yerleşik gibi davranan bir işlev yazmanız gerekiyorsa, bir prototip kullanın. Aksi takdirde, prototip kullanmayın.

Not: Perl 6 tamamen yenilenmiş ve çok kullanışlı prototiplere sahip olacaktır. Bu cevap yalnızca Perl 5 için geçerlidir.


Ama yine de arayanın ve abonenin aynı sayıda argüman kullandığına dair yararlı bir kontrol sağlıyorlar, peki bunun nesi yanlış?
Paul Tomblin

2
Hayır; genel fikir birliği, Perl işlevi prototiplerinin esasen hiçbir fayda sağlamadığı yönündedir. En azından Perl 5'te onlarla uğraşmayabilirsiniz. Perl 6 farklı (daha iyi) bir hikaye olabilir.
Jonathan Leffler

5
: Böyle Parametreler :: doğrula modül olarak validate argümanları daha iyi yolları vardır search.cpan.org/~drolsky/Params-Validate-0.91/lib/Params/...
Friedo

10
Düzeltme: dizi dilimleme bir liste döndürür , bu nedenle skaler bağlamdaki bir dizi dilimi, listenin son öğesini döndürür. foo()Baskıların ikinci-son çağrısı 2 çünkü bu, iki eleman diliminizdeki son elemandır. Olarak değiştirin my @array = qw(foo bar baz)ve farkı göreceksiniz. (Bir kenara gelecek olursak, bu yüzden dizileri / listeleri atma, gösterici kodda 0- veya 1 tabanlı sayısal dizilere başlatmıyorum. Bağlamlardaki indisler, sayımlar ve öğeler arasındaki karışıklık beni birden çok kez ısırdı. Aptal ama gerçek.)
pilcrow

2
@pilcrow: Sorunuzu a b cdaha net ifade etmek için kullanacağınız yanıtı düzenledim .
Flimm

30

Yukarıdaki iki afişe katılıyorum. Genel $olarak kullanımdan kaçınılmalıdır. Blok bağımsız değişkenleri (kullanırken prototipleri sadece yararlıdır &), Neználkovo ( *) ya da referans numuneler ( \@, \$, \%, \*)


Genel olarak, belki, ama iki istisnadan bahsetmek istiyorum: Birincisi, ($)prototip, faydalı olabilecek adlandırılmış bir tekli operatör yaratır (kesinlikle Perl onları yararlı bulur; ben de bazen var). İkincisi, yerleşikleri geçersiz kılarken (ister içe aktarma yoluyla ister CORE :: GLOBAL: :) kullanarak, genel olarak yerleşik olanın sahip olduğu prototipe bağlı kalmalısınız, bu a içerse bile $, yoksa programcıyı şaşırtabilirsiniz (kendiniz, hatta) yerleşik öğenin aksi takdirde skaler bağlam sağlayacağı liste bağlamıyla.
The Sidhekin

4

Bazı insanlar, bir Perl alt yordamı prototipine bakarken, bunun olmadığı bir şey ifade ettiğini düşünüyor:

sub some_sub ($$) { ... }

Perl için bu, ayrıştırıcının iki argüman beklediği anlamına gelir. Perl'in, hepsi sonraki koddan ne bekleneceğini bilen, yerleşikler gibi davranan alt programlar yaratmanıza izin verme yolu. Perlsub'da prototipler hakkında bilgi edinebilirsiniz

Belgeleri okumadan, insanlar prototiplerin çalışma zamanı argüman kontrolüne veya diğer dillerde gördüklerine benzer bir şeye atıfta bulunduğunu tahmin ediyor. İnsanların Perl hakkında tahmin ettiği çoğu şeyde olduğu gibi, yanlış oldukları ortaya çıkıyor.

Bununla birlikte, Perl v5.20 ile başlayarak, Perl, ben bunu yazarken deneysel, kullanıcıların ne beklediği ve ne beklediği gibi bir şey veren bir özelliğe sahip. Perl'in alt rutin imzaları , zaman bağımsız değişken sayımı, değişken atama ve varsayılan ayarı çalıştırır:

use v5.20;
use feature qw(signatures);
no warnings qw(experimental::signatures);

animals( 'Buster', 'Nikki', 'Godzilla' );

sub animals ($cat, $dog, $lizard = 'Default reptile') { 
    say "The cat is $cat";
    say "The dog is $dog";
    say "The lizard is $lizard";
    }

Prototipleri düşünüyorsanız, muhtemelen isteyeceğiniz özellik budur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.