2009-12-16 3 views
17

Jeśli chcę dodać metodę do klasy w Scala, muszę zrobić coś takiego:Zrozumieć dlaczego „pimp my biblioteki” został zdefiniowany w ten sposób w Scala

class RichFoo(f: Foo) { 
    def newMethod = f.bar() 
} 
object RichFoo { 
    implicit def foo2Rich(f: Foo) = new RichFoo(f) 
} 

Następnie f.newMethod spowoduje utworzenie RichFoo wystąpienie i wywołaj jego metodę.

Próbuję zrozumieć, dlaczego to nie zostało zdefiniowane w sposób podobny do Ruby:

override class Foo { 
    def newMethod = bar 
} 

Kompilator może spojrzeć na tej definicji i utworzyć klasę FooOverride metodą statyczną newMethod który pobiera parametr typu Foo i nazywa swoją metodę prętową. W ten sposób Scala wdraża cechy. Nadal muszę zaimportować paczkę zawierającą nadpisanie Foo, aby z niej skorzystać.

Wydaje się, że wymaga mniej pisania, nie wymaga wymyślania nazw i ma lepszą wydajność (bez wywoływania metody i tworzenia obiektu). Wszystko, co niejawna metoda konwersji, można zrobić wewnątrz dodatkowej metody.

Jestem pewien, że coś przeoczyłem i chciałbym dowiedzieć się, co.

+0

Does Ruby naprawdę się wykonać Scala w tym przypadku, czy może spekulować, że otwarta implementacja klasy może być tak szybki jak zamknięty? –

+3

Proponuję elewację, która wygląda tak, jakbyś ponownie otwierała klasę, ale w rzeczywistości po prostu wywołuje metody statyczne. Kompilator scala robi takie rzeczy przez cały czas (cechy są kompilowane do interfejsu i klasy za pomocą metod statycznych). Spekuluję, że jest to mniej kodowane i szybsze w porównaniu do obecnego niejawnego sposobu def. – IttayD

Odpowiedz

13

Istnieją inne zastosowania dla ukrytych konwersji innych niż tylko „pimp my bibliotekę” idiom, więc to naprawdę nie jest przypadek "dlaczego nie zrobili tego zamiast tego?", ale "dlaczego nie zrobili tego tak dobrze?". Z pewnością nie widzę powodu, dla którego składnia metod rozszerzenia nie mogłaby zostać dodana, jak sugerujesz, i prawdopodobnie byłaby nieco czystsza, ale nie ma zbyt dużej potrzeby, ponieważ język już obsługuje sposób osiągnięcia tego samego efektu. .

Aktualizacja październik 2011:

Jest nowa propozycja, aby dodać cukier składnię tego przypadku użycia: http://scala.github.com/sips/pending/implicit-classes.html

+0

Chyba masz rację. – IttayD

+1

Twoja odpowiedź jest poprawna. Chciałem zauważyć, że w rzeczywistości istnieje eksperymentalne rozszerzenie kompilatora Scala (zwanego wirtualizacją Scala), które obsługuje dodawanie metod do istniejących klas przez pisanie mniej kodu - poszukaj "def infix_ +" w tej klasie, aby znaleźć przykłady : https://github.com/TiarkRompf/virtualization-lms-core/blob/e11ee5c5c9eb5d00e38927f5f1722bc956e8615d/src/ppl/StringOps.scala Scala-zwirtualizowanych obsługuje również inne cechy, dla których najlepszą referencją (choć niekompletne) jest to : https://github.com/tiarkrompf/scala-virtualized/wiki – Blaisorblade

8

Jak zapobiec wprowadzaniu tej metody do zakresu bez konieczności wyraźnego importowania i nadawania jej nazwy? W rzeczywistości, w jaki sposób program może wiedzieć, jakie metody zostały dodane bez tego?

Kiedy używasz trzech różnych bibliotek, z których dwie dodają metody do trzeciej w sposób niekompatybilny, jak poradzisz sobie z tym bez implikowania pod kontrolą?

Poza tym lepsza wydajność nie jest możliwa, ponieważ JVM nie pozwala na zmianę istniejącej klasy. W najlepszym wypadku można uzyskać korzyść polegającą na tym, że nie trzeba wymyślać imienia i pisać go mniej kosztem braku możliwości kontrolowania tego, co się robi.

W końcowej nocie, jeśli chcesz krótki, można zrobić:

implicit def fooBar(f: Foo) = new { def newMethod = bar } 
+2

Zamiast tego importuję nadpisanie Foo. Nie sugerowałem zmiany klasy. Zasugerowałem, że foo.bar zostanie przekonwertowany na com.my.package.Foo.bar (foo). Twój ostatni przykład oznacza wywołanie newMethod za pomocą refleksji – IttayD

+4

'new {...} 'rzecz jest typem strukturalnym. Bądź ostrożny z tym: jego metody są wywoływane przez odbicie, co sprawia, że ​​jest powolny. Zobacz http://stackoverflow.com/questions/3119580/scala-equivalent-of-csharps-extension-methods/3119671#3119671 – Jesper