[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