2013-02-28 164 views
11

假設我已經定義了一個Erlang的演員是這樣的:Erlang與OOP對象有什麼不同?

counter(Num) -> 
    receive 
    {From, increment} -> 
     From ! {self(), new_value, Num + 1} 
     counter(Num + 1); 
    end.  

同樣,我已經定義了一個Ruby類是這樣的:

class Counter 
    def initialize(num) 
    @num = num 
    end 

    def increment 
    @num += 1 
    end 
end 

Erlang的代碼寫在一個實用的風格,採用尾遞歸維護狀態。但是,這種差異的有意義的影響是什麼?對我天真的眼睛來說,這兩件事的接口看起來差不多:你發送一條消息,狀態得到更新,並且你得到新狀態的表示。

函數式編程通常被描述爲與OOP完全不同的範例。但是Erlang的角色似乎確實做了對象應該做的事情:維護狀態,封裝並提供基於消息的接口。

換句話說,當我在Erlang之間傳遞消息時,它與在Ruby對象之間傳遞消息時有什麼不同?

我懷疑功能/ OOP二分法有比我看到的更大的結果。任何人都可以指出它們嗎?

讓我們拋開Erlang actor被VM安排的事實,因此可能會與其他代碼同時運行。我意識到這是Erlang和Ruby版本之間的主要區別,但這不是我所掌握的。其他語言(包括Ruby)可能會發生併發。儘管Erlang的併發性可能表現得非常不同(有時更好),但我並沒有真正問到性能差異。

相反,我對問題的功能與面向對象方面更感興趣。

+0

IMO的例子太小/分離,以顯示有意義的差異。很明顯,在這種情況下,*概念*差異很小。在這個微不足道的例子中,其他考慮因素更重要。 – 2013-03-01 00:34:49

回答

9

換句話說,當我在Erlang actor之間傳遞消息時,它與在Ruby對象之間傳遞消息時有什麼不同?

區別在於,在傳統語言(如Ruby)中,沒有消息傳遞,但在同一線程中執行方法調用,如果您有多線程應用程序,這可能會導致同步問題。所有線程都可以訪問其他線程內存。

在Erlang中,所有演員都是獨立的,改變另一個演員狀態的唯一方法是發送消息。沒有進程可以訪問任何其他進程的內部狀態。

+5

是的,這是這裏的核心區別。在Ruby和其他傳統語言中,他們**調用**消息傳遞,而在Erlang中則** **傳遞消息。 – rvirding 2013-03-01 21:37:31

+0

謝謝羅伯特! – 2013-03-01 23:47:07

0

恕我直言,這不是FP與OOP最好的例子。差異通常表現在訪問/迭代和鏈接對象上的方法/函數。另外,理解什麼是「當前狀態」在FP中可能會更好。

在這裏,您將兩種截然不同的技術相互對抗。一個碰巧是F,另一個是OO。

我可以馬上發現的第一個區別是內存隔離。消息在Erlang中被序列化,所以避免競爭條件更容易。

第二個是內存管理細節。在Erlang中,消息處理在發送者和接收者之間被分開。 Erlang虛擬機擁有兩組進程結構的鎖。因此,當發送者發送消息時,他獲取不阻止主進程操作的鎖(由主鎖訪問)。總而言之,它讓Erlang在Ruby方面更加柔和的實時性與完全隨機的行爲。

0

從外面看,演員與物體相似。它們通過消息來封裝狀態並與世界其他地方通信以操縱該狀態。

要了解FP的工作方式,您必須查看演員內部並瞭解其如何變化狀態。狀態是一個整數的例子太簡單了。我沒有時間提供完整的示例,但我會畫出代碼。通常情況下,一個演員循環看起來如下:

loop(State) -> 
    Message = receive 
    ... 
    end, 
    NewState = f(State, Message), 
    loop(NewState). 

從OOP最重要的區別在於有沒有變量突變,即NewState從國家獲得的,並且可以共享大部分與它的數據,但狀態變量總是保持不變。

這是一個不錯的屬性,因爲我們從不破壞當前狀態。函數f通常會執行一系列轉換以將狀態轉換爲NewState。只有當它完全成功時,我們才能通過調用循環(NewState)來替換舊狀態。 所以重要的好處是我們國家的一致性。

我發現的第二個好處是代碼更乾淨,但需要一些時間才能習慣它。通常,由於您無法修改變量,因此您必須將代碼分成許多非常小的函數。這其實很好,因爲你的代碼將被很好地考慮。

最後,由於您無法修改變量,因此更容易推理代碼。對於可變對象,您永遠無法確定對象的某個部分是否會被修改,並且如果使用全局變量,它會逐漸變得更糟。做FP時你不應該遇到這樣的問題。

要嘗試一下,您應該嘗試通過使用純erlang結構(而不​​是演員,ets,mnesia或proc dict)以功能方式處理一些更復雜的數據。另外,你也可以用紅寶石嘗試它this

0

Erlang包括Alan Kay的OOP(Smalltalk)的消息傳遞方法和Lisp的函數式編程。

您在示例中描述的是OOP的消息方法。發送消息的Erlang進程與Alan Kay的對象發送消息類似。順便說一下,你可以檢索到這個概念,也在Scratch中實現,其中並行運行的對象在它們之間發送消息。

函數式編程是如何編寫進程的代碼。例如,Erlang中的變量不能被修改。一旦他們被設置,你只能閱讀它們。你也有一個列表數據結構,它與Lisp列表非常相似,並且你有受到Lisp lambda啓發的fun

Erlang中傳遞的消息和另一方的函數是兩個獨立的東西。在編寫真實生活的erlang應用程序時,您花了98%的時間進行函數式編程,2%的時間考慮消息傳遞,主要用於可伸縮性和併發性。換句話說,當你遇到複雜的編程問題時,你可能會使用Erlang的FP端來實現算法的細節,並使用消息傳遞來實現可伸縮性,可靠性等。

0

你覺得這是什麼:

thing(0) -> 
    exit(this_is_the_end); 
thing(Val) when is_integer(Val) -> 
    NewVal = receive 
     {From,F,Arg} -> NV = F(Val,Arg), 
         From ! {self(), new_value, NV}, 
         NV; 
     _ -> Val div 2 
    after 10000 
     max(Val-1,0) 
    end, 
    thing(NewVal). 

當你產卵的過程中,它會通過自己的生活,降低其價值,直到它達到的值0和發送消息{「EXIT」,this_is_the_end }鏈接到它,除非你採取執行類似的保健任何過程:

ThingPid ! {self(),fun(X,_) -> X+1 end,[]}. 
% which will increment the counter 

ThingPid ! {self(),fun(X,X) -> 0; (X,_) -> X end,10}. 
% which will do nothing, unless the internal value = 10 and in this case will go directly to 0 and exit 

在這種情況下,您可以看到「對象」本身與其他應用程序同時存在,它可以在幾乎沒有任何代碼的情況下與外部進行交互,並且外部可以請求他執行一些操作不知道你編寫和編譯代碼的時間。

這是一個愚蠢的代碼,但有一些原則,用於實現應用程序,如mnesia事務,行爲...恕我直言,這個概念是真的不同,但你必須嘗試思考不同,如果你想使用它正確。我非常肯定可以在Erlang中編寫「OOPlike」代碼,但避免併發性是非常困難的:o)並且最終沒有優勢。看一看OTP原理,它給出了Erlang應用程序體系結構(監督樹,「1個單一客戶機服務器」池,鏈接進程,受監控進程,當然還有模式匹配單個分配,消息,節點集羣等)的跟蹤。 )。