2016-08-24 10 views
9

Przeczytałem w książce, że "nie można tworzyć tradycyjnych" klas "w julia metodami single-wysyłka stylu jak obj.myfunc() "... i myślałem, że brzmiało to bardziej jak wyzwanie niż fakt: pJak utworzyć klasę "pojedynczej wysyłki, obiektowej" w julia, która zachowuje się jak standardowa klasa Java z publicznymi/prywatnymi polami i metodami

Więc oto moja JavaClass typ z publicznych/prywatnych pól i metod po prostu dla czystej przerażeniu czynnik, który miał w Julii coś tak brzydkiego, po tym, jak wszyscy udali się, aby go uniknąć:

type JavaClass 

    # Public fields 
    name::String 

    # Public methods 
    getName::Function 
    setName::Function 
    getX::Function 
    getY::Function 
    setX::Function 
    setY::Function 

    # Primary Constructor - "through Whom all things were made." 
    function JavaClass(namearg::String, xarg::Int64, yarg::Int64) 

     # Private fields - implemented as "closed" variables 
     x = xarg 
     y = yarg 

     # Private methods used for "overloading" 
     setY(yarg::Int64) = (y = yarg; return nothing) 
     setY(yarg::Float64) = (y = Int64(yarg * 1000); return nothing) 

     # Construct object 
     this = new() 
     this.name = namearg 
     this.getName =() -> this.name 
     this.setName = (name::String) -> (this.name = name; return nothing) 
     this.getX =() -> x 
     this.getY =() -> y 
     this.setX = (xarg::Int64) -> (x = xarg; return nothing) 
     this.setY = (yarg) -> setY(yarg) #Select appropriate overloaded method 

     # Return constructed object 
     return this 
    end 

    # a secondary (inner) constructor 
    JavaClass(namearg::String) = JavaClass(namearg, 0,0) 
end 

Przykład użycia:

julia> a = JavaClass("John", 10, 20); 

julia> a.name # public 
"John" 

julia> a.name = "Jim"; 

julia> a.getName() 
"Jim" 

julia> a.setName("Jack") 

julia> a.getName() 
"Jack" 

julia> a.x # private, cannot access 
ERROR: type JavaClass has no field x 

julia> a.getX() 
10 

julia> a.setX(11) 

julia> a.getX() 
11 

julia> a.setY(2) # "single-dispatch" call to Int overloaded method 

julia> a.getY() 
2 

julia> a.setY(2.0) 

julia> a.getY() # "single-dispatch" call to Float overloaded method 
2000 

julia> b = JavaClass("Jill"); # secondary constructor 

julia> b.getX() 
0 

Zasadniczo, konstruktor staje się zamknięcie, które jest jak jeden tworzy „prywatny” pól i metod/przeciążenia. Jakieś myśli? (inne niż "OMG Dlaczego?" Dlaczego miałbyś to robić? ")
Jakieś inne podejście?
Jakieś scenariusze, które można przewidzieć, jeśli może to nie zadziałać spektakularnie?

+1

Nie wiem, czy jest to odpowiednie dla StackOverflow ... ale jest to interesujące. –

+1

Po prostu chciałeś się tym podzielić ... Ale ja też chciałbym. –

+2

Jestem pewien, że * ktoś * będzie szukał tego konkretnego pytania na stackoverflow w pewnym momencie. Jest to pytanie, które jest nieuniknione! Tak więc, chociaż format może być nieco niekonwencjonalny, prawdopodobnie jest to więcej niż artykuł na stackoverflow :) –

Odpowiedz

23

Chociaż nie jest to idiomatyczny sposób tworzenia przedmiotów i metod w Julii, nie ma w tym nic złego. W dowolnym języku z zamknięciami możesz zdefiniować własne "systemy obiektowe" w ten sposób, na przykład zobacz wiele systemów obiektowych, które zostały opracowane w ramach Schematu.

W julia v0.5 jest to wyjątkowo prosty sposób, ponieważ zamknięcia stanowią automatycznie przechwycone zmienne jako pola obiektu. Na przykład:

julia> function Person(name, age) 
     getName() = name 
     getAge() = age 
     getOlder() = (age+=1) 
     ()->(getName;getAge;getOlder) 
     end 
Person (generic function with 1 method) 

julia> o = Person("bob", 26) 
(::#3) (generic function with 1 method) 

julia> o.getName() 
"bob" 

julia> o.getAge() 
26 

julia> o.getOlder() 
27 

julia> o.getAge() 
27 

To dziwne, że musisz zwrócić funkcję, aby to zrobić, ale tak jest. Jest to możliwe dzięki wielu optymalizacjom, takim jak język określający precyzyjne typy pól, więc w niektórych przypadkach możemy nawet wstawić te "wywołania metod". Kolejną fajną cechą jest to, że dolna linia funkcji kontroluje, które pola są "publiczne"; wszystko tam wymienione stanie się polem obiektu. W takim przypadku otrzymasz tylko metody, a nie zmienne nazwy i wieku. Ale jeśli dodałeś do listy name, będziesz mógł również wykonać o.name. Oczywiście metody te są również wielostronne; możesz dodać wiele definicji dla getOlder itd. i będzie działać tak, jak oczekujesz.

+2

Bardzo interesujące! Zwłaszcza ten fragment o przechwyconych zmiennych staje się polami! Jednak widzę problem z tym podejściem: dziedziny te wydają się niezmienne, co jest sprzeczne z celem "publicznych" dziedzin; również, wydaje się, że ich wartości stają się "pudełkowe", jeśli istnieją metody "seter", a nie tylko "getter", co prowadzi do dalszych komplikacji (np. jeśli "wiek" zostanie dodany do "publicznych" zmiennych powyżej, 'o.age + 1' kończy się niepowodzeniem z 'ERROR: MethodError: no method matching + (:: Core.Box, :: Int64)'). Czy to podejście może być w jakiś sposób? –

+2

Podoba mi się fakt, że może to prowadzić do potencjalnie "wywoływanego" obiektu (np. Jeśli ostatnim argumentem w instrukcji złożonej jest sama funkcja)! To prawie jak tworzenie "obiektu", który ma również przeciążony operator '()', jak Functors w C++. –

+1

PS: to zaszczyt spotkać Stwórcę. (Przebacz mi, o Panie, nie jestem godny!) –

Powiązane problemy