[erlang-questions] Re: Concept of Side-effect

Jayson Vantuyl kagato@REDACTED
Fri Sep 18 14:40:53 CEST 2009


Actually, I'm not entirely sure that an exception would be a side  
effect.  It doesn't get "returned" like a normal value, but I don't  
see that it changes state any more than a return value does.

Put another way, a function has "no side-effects" if all the data goes  
in through the parameters and a result comes out the end--without  
anything else being touched.  This means that we can safely optimize  
that call away, or run with a thousand different inputs in parallel  
(on a bunch of processors), or do any number of things without worry  
about two parallel executions of it stepping on each others toes.

So, taking another stab at Kaiduan's question, maybe it's best  
illustrated by contrast.  Having "no side-effects" is most important  
when you have concurrent code.

In Erlang, no two processes share state that can be changed.  If you  
change state in one process, it never changes in another one.  In this  
way, a process has no "side effects" unless you choose to make some.

Contrast this with the normal way of using shared memory with  
threads.  In these languages, you have multiple threads trying to lock  
access to shared resources (or using complex lockless methods).  The  
complications of avoiding deadlocks or generating correct behavior in  
threaded systems are very difficult compared to Erlang's isolation.

Instead of having a bunch of processes fighting over shared resources,  
we let resources be owned by individual processes only, but give a  
powerful way to communicate among them.  This isolation is embodied in  
the concept that no simple Erlang function can touch another process's  
state, thus there are no "side-effects" that the other process has to  
worry about.  All side effects are contained in a few operations that  
are easily handled.

Understanding the impact of delivering messages to mailboxes and  
spawning processes (which is 99% of side-effects in Erlang code) is  
much easier to debug and much easier to understand than finding race  
conditions with complex locking regimes, implementing even the  
simplest of lockless algorithms portably, or using system IPC to  
manage concurrency.  With the possible exception of Software  
Transactional Memory, there doesn't seem to be much of anything that  
comes closer to simplifying concurrent programming.

On Sep 18, 2009, at 4:52 AM, Ovidiu Deac wrote:

> Exceptions too?
>
> On Fri, Sep 18, 2009 at 4:47 AM, Jayson Vantuyl <kagato@REDACTED>  
> wrote:
>> A small addendum.
>>
>> Note that calling unsafe functions can create side-effects.  Things  
>> like
>> gen_server:call, for example, send messages.  So you need to be  
>> careful with
>> library functions.
>>
>> Thinking a bit, other times that you can modify state:
>>
>> * Changing the process dictionary (most people don't really do this)
>> * ETS tables (messages in disguise)
>> * DETS tables (messages in disguise)
>> * Network Connections (messages in disguise)
>> * digraphs (messages in disguise)
>>
>> On Sep 17, 2009, at 6:35 PM, Jayson Vantuyl wrote:
>>
>>> I'll do better.  Here's an example that actually is necessary.
>>>
>>> Assume you have two processes.  One updates a record in Mnesia,  
>>> the other
>>> receives an acknowledgement that it did it.
>>>
>>> Mnesia can replay a transaction in times of extreme contention.   
>>> Here's a
>>> buggy version of a function that charges some account.  Look at  
>>> the fun()
>>> inside.  It has the side-effect that it sends a message to another  
>>> process.
>>>
>>>> charge_account(Requestor,UserId,Amount) ->
>>>>  {atomic,ok} = mnesia:transaction(
>>>>   fun() ->
>>>>     [ Current ] = mnesia:read(account,UserId),
>>>>     OldAmount = Current#account.amount,
>>>>     New = Current#account{ amount = OldAmount - Amount },
>>>>     ok = mnesia:write(New),
>>>>     Requestor ! {updated,New},
>>>>     ok
>>>>   end
>>>>  ).
>>>
>>> This function will potentially send the message to Requestor  
>>> multiple
>>> times if the transaction has to be retried.
>>>
>>> If you want to do this correctly, you can simply modify the  
>>> function like
>>> this:
>>>
>>>> charge_account(Requestor,UserId,Amount) ->
>>>>  {atomic,Result} = mnesia:transaction(
>>>>   fun() ->
>>>>     [ Current ] = mnesia:read(account,UserId),
>>>>     OldAmount = Current#account.amount,
>>>>     New = Current#account{ amount = OldAmount - Amount },
>>>>     ok = mnesia:write(New),
>>>>     New
>>>>   end,
>>>>   Requestor ! {updated,Result},
>>>>  ).
>>>
>>> The inner fun() has no side-effects and can now be safely retried by
>>> Mnesia.
>>>
>>> This is only one instance where side-effects matter.  The  
>>> important thing
>>> to remember is that state data in Erlang takes the form of  
>>> recursion,
>>> processes and messages.  If you don't create recurse with a  
>>> modified value,
>>> create a process, or send a message, then no state is changed.   
>>> Even when
>>> you recurse, your state only affects a single process.  This  
>>> property makes
>>> it very easy to create very stable programs, because you can  
>>> contain the
>>> places that state can get corrupted or lost.
>>>
>>> Hopefully this helps.
>>>
>>> On Sep 17, 2009, at 6:17 PM, Kaiduan Xie wrote:
>>>
>>>> Thanks all for the reply. Can someone provide an example in code?  
>>>> For
>>>> example, a side-effect free function, and its counterpart function
>>>> with side-effect.
>>>>
>>>> Thanks,
>>>>
>>>> kaiduan
>>>>
>>>> On Thu, Sep 17, 2009 at 11:07 AM, Gene Tani <gene.tani@REDACTED>  
>>>> wrote:
>>>>>
>>>>>
>>>>> On Sep 16, 3:26 pm, Kaiduan Xie <kaidu...@REDACTED> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Can someone explain what does side-effect means in Erlang? What  
>>>>>> is
>>>>>> side-effect free function, and why we need to write side-effect  
>>>>>> free
>>>>>> function? A concrete example is preferred.
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> kaiduan
>>>>>>
>>>>>> ________________________________________________________________
>>>>>> erlang-questions mailing list. Seehttp://www.erlang.org/faq.html
>>>>>> erlang-questions (at) erlang.org
>>>>>
>>>>> http://blog.tornkvist.org/blog.yaws?id=1239107937892262
>>>>>
>>>>>
>>>>> http://www.cs.chalmers.se/Cs/Grundutb/Kurser/ppxt/HT2007/general/languages/armstrong-erlang_history.pdf
>>>>> (PDF page 14)
>>>>>
>>>>> and a FP vs. OO debate:
>>>>>
>>>>> http://news.ycombinator.com/item?id=493963
>>>>>
>>>>> ________________________________________________________________
>>>>> erlang-questions mailing list. See http://www.erlang.org/faq.html
>>>>> erlang-questions (at) erlang.org
>>>>>
>>>>>
>>>>
>>>> ________________________________________________________________
>>>> erlang-questions mailing list. See http://www.erlang.org/faq.html
>>>> erlang-questions (at) erlang.org
>>>>
>>>
>>>
>>>
>>> --
>>> Jayson Vantuyl
>>> kagato@REDACTED
>>>
>>>
>>>
>>
>>
>>
>> --
>> Jayson Vantuyl
>> kagato@REDACTED
>>
>>
>>
>>
>> ________________________________________________________________
>> erlang-questions mailing list. See http://www.erlang.org/faq.html
>> erlang-questions (at) erlang.org
>>
>>
>
> ________________________________________________________________
> erlang-questions mailing list. See http://www.erlang.org/faq.html
> erlang-questions (at) erlang.org
>



-- 
Jayson Vantuyl
kagato@REDACTED





More information about the erlang-questions mailing list