Whether this is surprising to you or not depends entirely what language you
are coming from. For Matlab and R users, this is a significant difference.
For people coming from C, C++, Fortran, Python, Ruby, Perl, Java, and Lisp,
this is unsurprising. You can easily implement the non-mutating behavior
starting from pass-by-sharing semantics. Starting from Matlab/R
pass-by-value semantics, it's basically impossible to recover efficiency
and avoid copying reliably – and any mechanisms to do so are complicated
and hard to reason about (copy-on-write is one such mechanism). This is one
of the main reasons why people write MEX extensions in Matlab and C/C++
extensions in R – so that they can modify arrays without copying them and
have fast for loops. Since Julia aims to never force you to use a lower
level language, the only real choice is the way we do it.

On Fri, Dec 26, 2014 at 4:04 PM, Páll Haraldsson <[email protected]>
wrote:

>
> I wander if the convention should have been made the other way as not all
> will know it at first..
>
> If you do not want your arguments touched then you can trivially make a
> non-mutating wrapper using the similar function. It seems that could have
> been automated.. Maybe you can with a macro?
>
> Would it be easy to give a warning or an error for functions that are
> mutating? Or really, if it can be detected then shouldn't the function be
> renamed to the ! variant and a wrapper be made?
>
> Best regards,
> Palli.
>
>
> On Friday, December 26, 2014 8:42:18 PM UTC, Tomas Lycken wrote:
>>
>> Glad to be of service! =)
>>
>> Languages treat both aliasing and argument passing differently, so it
>> really just takes a little while to experiment and see how this language
>> plays out what you're trying to do. For what it's worth, Julia also has
>> a style convention to end all method names with a bang ("!") if they mutate
>> their arguments. So with your first example, the function could have been
>> named square!(arg), and then users of that function would be immediately
>> aware that arg would be changed. This convention isn't really enforced in
>> any way (except code review) - it's perfectly valid Julia to mutate
>> function arguments even if the function name doesn't end with ! - but the
>> core libraries as well as most packages do follow it.
>>
>> Happy coding!
>>
>> // Tomas
>>
>> On Friday, December 26, 2014 9:33:12 PM UTC+1, Bradley Setzler wrote:
>>>
>>> Thanks Tomas, the similar command will be very useful in avoiding this
>>> issue.
>>>
>>> Thank you also for a thoughtful and informative response, Tomas.
>>>
>>> Bradley
>>>
>>> PS - For what it's worth, R does not have this behavior.
>>>
>>>
>>>
>>> On Friday, December 26, 2014 2:05:44 PM UTC-6, Tomas Lycken wrote:
>>>>
>>>> The main reason is performance; passing and aliasing arrays this way
>>>> (those are two different concepts, which work together to make this
>>>> particular example a little confusing) allow for writing code that is as
>>>> fast as possible, by leaving the coder in control of when a copy is made
>>>> and when it is not. A more idiomatic way of writing your square function,
>>>> which would do what you expect, would be
>>>>
>>>> ```
>>>> function square(A)
>>>>     A2 = similar(A)
>>>>     for i = 1:length(A)
>>>>         A2[i] = A[i]^2
>>>>     end
>>>>     A2
>>>> end
>>>> ```
>>>>
>>>> The funciton `similar` allocates new memory for an array of similar
>>>> size and type as `A`. You could also have left your entire method untouch
>>>> except setting `inner_var = copy(arg)`, but this would have meant both
>>>> reading and writing more to memory than you need to. As you see, Julia's
>>>> behavior allows you to write more performant code than what you'd do
>>>> otherwise.
>>>>
>>>> // Tomas
>>>>
>>>> On Friday, December 26, 2014 8:58:04 PM UTC+1, Bradley Setzler wrote:
>>>>>
>>>>> Why would you want this behavior? How could you possibly benefit from
>>>>> modifying X anytime you modify Y just because Y=X initially? If I wanted 
>>>>> to
>>>>> modify X, I would modify X itself, not Y.
>>>>>
>>>>> Bradley
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Friday, December 26, 2014 1:53:12 PM UTC-6, John Myles White wrote:
>>>>>>
>>>>>> This is aliasing. Almost all languages allow this.
>>>>>>
>>>>>>  -- John
>>>>>>
>>>>>> Sent from my iPhone
>>>>>>
>>>>>> On Dec 26, 2014, at 2:49 PM, Bradley Setzler <[email protected]>
>>>>>> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> I cannot explain this behavior. I apply a function to a variable in
>>>>>> the workspace, the function initializes its local variable at the 
>>>>>> workspace
>>>>>> variable, then modifies the local variable and produces the desired 
>>>>>> output.
>>>>>> However, it turns out the Julia modifies both the local and workspace
>>>>>> variable with each operation on the local variable. Only the local 
>>>>>> variable
>>>>>> is supposed to be modified.
>>>>>>
>>>>>> *This is very dangerous behavior, as Julia is modifying the data
>>>>>> itself between performing operations on the data; the data itself is
>>>>>> supposed to remain fixed between operations on it.*
>>>>>>
>>>>>> *Minimal working example:*
>>>>>>
>>>>>> data=[1,2,3]
>>>>>> function square(arg)
>>>>>>     inner_var = arg
>>>>>>     for i=1:length(inner_var)
>>>>>>         inner_var[i] = inner_var[i]^2
>>>>>>     end
>>>>>>     return inner_var
>>>>>> end
>>>>>> output=square(data)
>>>>>>
>>>>>> julia> print(data)
>>>>>>
>>>>>> [1,4,9]
>>>>>>
>>>>>> The data has been squared due to the local variable, which was
>>>>>> initialized at the data values, being squared. Now, if i wish to apply a
>>>>>> different function to the data, the result will be incorrect because the
>>>>>> data has been modified unintentionally.
>>>>>>
>>>>>> How long has Julia been doing this? Was this behavior intentional?
>>>>>> Bradley
>>>>>>
>>>>>>
>>>>>>

Reply via email to