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 >>>>>> >>>>>> >>>>>>
