Function argument intent

627 views
Skip to first unread message

Espen Myklebust

unread,
Jun 18, 2013, 10:11:04 AM6/18/13
to julia...@googlegroups.com
I just recently discovered Julia and have not yet started using it, but nevertheless after reading the manual (ver 0.2-dev) I have a question.
 
Being a Fortran user I'm used to function arguments being passed by reference as Julia also does, however I could not find any way of specifying argument intent.
I'm not sure if this is common CS lingo and doing a quick google search I could only find references to Fortran (example of search string: function argument intent),
but as I know that many newer Fortran language features are inspired by Ada features I found this wikibook section explaining what I mean (it is called parameter modes there):
 
A brief explanation of how this works: you (optionally) declare each function argument to have read-only, write-only, or full access.
In Ada apparently read-only is default, whereas in Fortran full access is default. In addition Fortran has the "value" argument attribute that tells the compiler that you want to pass by value instead.
In my experience this way of limiting the possible usage of a function's arguments is very helpful for catching errors, and I think it also aids optimization.
 
So is there any way to do the same in Julia?
 
/EM

Stefan Karpinski

unread,
Jun 18, 2013, 11:49:49 AM6/18/13
to Julia Users
There isn't any way to do this in Julia. In general, we don't statically check for things the way Fortran, C or Java do – programming Julia is much more like programming Python, Ruby or Matlab. There are no read-only or write-only references to objects. (There are const bindings, but that only affects the ability to change what object the binding refers to, not what you can do with the bound value.)

Note that I'm not ruling out (or objecting to) the possibility of doing something like this in the future, but so far we haven't gotten into any kind of static checking, and doing so is a major undertaking, as well as a massive complication to the basic language.

Espen Myklebust

unread,
Jun 18, 2013, 1:29:58 PM6/18/13
to julia...@googlegroups.com
I'm not sure what exactly is done in a "static check," but if it means that the code is analyzed to check if any assignments are performed I guess that would give a (small?) performance hit.
How are immutable types ensured to not mutate? Perhaps the same check(s) could be done for arguments with intent/mode 'in'?
 
Although I agree competely on the decision to use call-by-reference model as default, I think it would be really nice if Julia could provide a way to pass-by-value as well (as explicit local copies sometimes can cause confusion).

Stefan Karpinski

unread,
Jun 18, 2013, 2:49:19 PM6/18/13
to Julia Users
On Tue, Jun 18, 2013 at 1:29 PM, Espen Myklebust <sykl...@gmail.com> wrote:
I'm not sure what exactly is done in a "static check," but if it means that the code is analyzed to check if any assignments are performed I guess that would give a (small?) performance hit.

The performance hit isn't really the issue. It's the extensive complication to the language that this would cause. Currently, you either have a reference to something or you don't. All places that have a reference to something can do all the same things with it. It's simple, it's clear, it's straightforward. Adding "intent" would multiply all types by three, adding implicit read-only and write-only variant of each type. Checking that these variations are respected is hard and would cause the language to become quite finicky and annoying to use – you could only use read-only values in read-only positions of any function that you call on it. People would start getting subtle errors for calling functions on values in some contexts but not others. Seemingly innocuous changes in certain parts of code would suddenly cause problems in apparently unrelated code. Ada is a notoriously obstinate language to argue with and that sort of obstinacy is not Julia's style.

[As Leah Hanson observed: "I like that Julia uses the type system in all the ways that don't end with the programmer arguing with the compiler."]

How would intent annotations interact with multiple dispatch? What if one method of a generic function uses an argument as read-only while another method uses it as write-only? Can you call that function on a read-only value? Can you call it on a write-only value? A read-write value? Does it depend on which method actually gets called? Or does dispatch apply to intent variants? Can you have methods that are distinguishable only by the intent of some argument and which one applies is chosen that way?
 
How are immutable types ensured to not mutate? Perhaps the same check(s) could be done for arguments with intent/mode 'in'?

Again, this is a completely different thing: const applies to bindings, not values. Since bindings are limited to a given scope, they're easier to reason about for both compilers and programmers. Currently, only global constness is even paid any attention to – and we don't even enforce it! You can redefine a const global and you'll just get a warning:

julia> const x = 1
1

julia> x = 2
Warning: redefining constant x
2
 
What is enforced is that the type of a global constant can't change:

julia> x = "foo"
ERROR: invalid redefinition of constant x

The const declaration is really about letting the compiler generate efficient code.
 
Although I agree competely on the decision to use call-by-reference model as default, I think it would be really nice if Julia could provide a way to pass-by-value as well (as explicit local copies sometimes can cause confusion).

Again, this would be a massive language complication. The Julian approach is to pick one good way of doing things and stick with it – and make sure it's really great. There are *only* dynamic semantics in the language, but you get static performance most of the time. There is only one dispatch mechanism but it's very powerful. Similarly, there are only reference semantics, no value semantics, but since we support immutable types, you can get the advantages of value semantics without needing to switch mental models based on how a type is declared. And you don't need to have two parallel types systems with incompatible semantics like Java and C# do.

I hate to say "No" so much, but saying no to features is probably the most important thing you can do in language design.

Espen Myklebust

unread,
Jun 19, 2013, 10:49:56 AM6/19/13
to julia...@googlegroups.com
Sorry for the late reply, but here goes:

On Tuesday, June 18, 2013 8:49:19 PM UTC+2, Stefan Karpinski wrote:
On Tue, Jun 18, 2013 at 1:29 PM, Espen Myklebust <sykl...@gmail.com> wrote:
I'm not sure what exactly is done in a "static check," but if it means that the code is analyzed to check if any assignments are performed I guess that would give a (small?) performance hit.
Adding "intent" would multiply all types by three, adding implicit read-only and write-only variant of each type.
 
I can't say anything regarding Ada, but what you say is not true in the case of Fortran, at least. I suspect that you are not very familiar with (modern, ie. F95 and later) Fortran so I'll give a very superficial account for how this works:
In a procedure (Fortran has two types; subroutines and functions) you can declare the "intent" of _dummy_ arguments as "in", "out" or "inout". This has *nothing* to do with the _actual_ arguments passed to the procedure in a call. No variables are declared with "intent", only dummy arguments. The Fortran standard does not specify how things should be implemented, but it is my impression that most compilers check that the intents of procedure arguments are obeyed when processing the source code (in the compiler front-end) and it does not necessarily have any effect on the resulting object/machine code. It is there for aiding the programmer convey to the compiler exactly what he intends to do with the passed arguments, but because of this it can help the comipler optimize the code better in which case the resulting code of course may be different than without using it.
 
People would start getting subtle errors for calling functions on values in some contexts but not others. Seemingly innocuous changes in certain parts of code would suddenly cause problems in apparently unrelated code.
 
In my experience it is precisely the opposite (probably due your understanding of the feature being different from how it works in Fortran). The main reason that I asked if it is possible to declare "intent" in Julia is that it helps me (or rather the compiler) catch errors. It is not uncommon, especially when coming back to a code after some time, that I try to use variables in a manner that is incompatible with how I initially planned the function. When the compiler then complains about this it is usually a good thing as I then avoid possible hard to find errors due to procedure side effects.
 
 
How would intent annotations interact with multiple dispatch? What if one method of a generic function uses an argument as read-only while another method uses it as write-only? Can you call that function on a read-only value? Can you call it on a write-only value? A read-write value? Does it depend on which method actually gets called? Or does dispatch apply to intent variants? Can you have methods that are distinguishable only by the intent of some argument and which one applies is chosen that way?
 
This is of no concern with the above sketched mechanism since there is no dependence on the actual arguments. Of course a good compiler would complain if you provide a parameter (a Fortran constant) for an argument that the procedure has write access for (intent "out" or "inout"), but I must say I prefer a compiler error over a run-time error.
 
How are immutable types ensured to not mutate? Perhaps the same check(s) could be done for arguments with intent/mode 'in'?

Again, this is a completely different thing: const applies to bindings, not values. Since bindings are limited to a given scope, they're easier to reason about for both compilers and programmers. Currently, only global constness is even paid any attention to – and we don't even enforce it! You can redefine a const global and you'll just get a warning:
 
This could be the only thing that would happen to an "intent in" argument also (and the same if one would try evaluate an "intent out" variable), at least to begin with (as long as you don't enforce const either).
A side question: I was asking about immutable composite types which are declared with the immutable keyword. Is that equivalent to an instance of a "regular" composite type declared with const?
 
 
The const declaration is really about letting the compiler generate efficient code.
 That is precisely what I think can be done with providing argument intent; an argument could be treated as a const within the function allthough it's really not. 
 
 
Although I agree competely on the decision to use call-by-reference model as default, I think it would be really nice if Julia could provide a way to pass-by-value as well (as explicit local copies sometimes can cause confusion).

Again, this would be a massive language complication. The Julian approach is to pick one good way of doing things and stick with it – and make sure it's really great. There are *only* dynamic semantics in the language, but you get static performance most of the time. There is only one dispatch mechanism but it's very powerful. Similarly, there are only reference semantics, no value semantics, but since we support immutable types, you can get the advantages of value semantics without needing to switch mental models based on how a type is declared. And you don't need to have two parallel types systems with incompatible semantics like Java and C# do.
 
I never programmed either Java or C#, but it sure sounds like an laborious approach... Again, I can only say what is the case in Fortran which, being a rather simplistic(in a good sense) language in this respect, doesn't make a programmes life harder by such intricate constructs. When a (dummy) argument is declared with the "value" attribute the compiler simply makes a local copy of the variable to the procedure scope, just as Matlab (and I suppose C) does. The reason I suggested it was that i thought this would be relatively straight forward to implement; it could probably be done in a "macro-style" (not a reference to Julia macros, as I havent studied them yet) where code for copying the actual argument is inserted and the reference pointer changed to the copy instead of the actual argument.
 
Perhaps you ask yourself why I'm not just using Fortran. The thing is that I'm also using Matlab a lot, and it is for that part of my work I'm looking into switching to Julia, and since it seems like the language is still in an "early stage" of development (?) I thought that perhaps it would be possible to have some of the features that I find to be very nice about Fortran in Julia... I get that saying no is imporant, but I just wanted to try to clear up what seems to me being a misunderstanding of concepts.

Stefan Karpinski

unread,
Jun 19, 2013, 12:51:08 PM6/19/13
to Julia Users
On Wed, Jun 19, 2013 at 10:49 AM, Espen Myklebust <sykl...@gmail.com> wrote:

In a procedure (Fortran has two types; subroutines and functions) you can declare the "intent" of _dummy_ arguments as "in", "out" or "inout". This has *nothing* to do with the _actual_ arguments passed to the procedure in a call. No variables are declared with "intent", only dummy arguments.

I'm not sure what dummy arguments means here. They're never used?
 
The Fortran standard does not specify how things should be implemented, but it is my impression that most compilers check that the intents of procedure arguments are obeyed when processing the source code (in the compiler front-end) and it does not necessarily have any effect on the resulting object/machine code. It is there for aiding the programmer convey to the compiler exactly what he intends to do with the passed arguments, but because of this it can help the comipler optimize the code better in which case the resulting code of course may be different than without using it.

In a dynamic language, you cannot generally statically check everything. I think this complicates this issue more than you may be realizing.

People would start getting subtle errors for calling functions on values in some contexts but not others. Seemingly innocuous changes in certain parts of code would suddenly cause problems in apparently unrelated code.
 
In my experience it is precisely the opposite (probably due your understanding of the feature being different from how it works in Fortran). The main reason that I asked if it is possible to declare "intent" in Julia is that it helps me (or rather the compiler) catch errors. It is not uncommon, especially when coming back to a code after some time, that I try to use variables in a manner that is incompatible with how I initially planned the function. When the compiler then complains about this it is usually a good thing as I then avoid possible hard to find errors due to procedure side effects.

I should clarify that what I meant is that people would get subtle *compiler* errors that would be annoying and hard to figure out. The obvious response is that when that happens they would otherwise be getting subtle bugs that would be even harder to figure out. While that's sometimes the case, there are a lot of situations where you know you can appear to violate read/write "rules" but actually be just fine.
 
How would intent annotations interact with multiple dispatch? What if one method of a generic function uses an argument as read-only while another method uses it as write-only? Can you call that function on a read-only value? Can you call it on a write-only value? A read-write value? Does it depend on which method actually gets called? Or does dispatch apply to intent variants? Can you have methods that are distinguishable only by the intent of some argument and which one applies is chosen that way?
 
This is of no concern with the above sketched mechanism since there is no dependence on the actual arguments. Of course a good compiler would complain if you provide a parameter (a Fortran constant) for an argument that the procedure has write access for (intent "out" or "inout"), but I must say I prefer a compiler error over a run-time error.

I can't really tell what the sketched mechanism is, but I'm pretty sure this is not possible to sweep this issue under the carpet like this unless your mechanism is purely for documentation and not checked at all. Example:

abstract Abstract
type Concrete1 <: Abstract field end
type Concrete2 <: Abstract field end

foo(in x::Abstract) = bar(x)
bar(out x::Concrete1) = (x.field = "hello"; return)
bar(in x::Concrete2) = return

Is this an error or not? You certainly can't tell at compile time. It might be possible to make this work, but it's not simple.
 
How are immutable types ensured to not mutate? Perhaps the same check(s) could be done for arguments with intent/mode 'in'?

Again, this is a completely different thing: const applies to bindings, not values. Since bindings are limited to a given scope, they're easier to reason about for both compilers and programmers. Currently, only global constness is even paid any attention to – and we don't even enforce it! You can redefine a const global and you'll just get a warning:
 
This could be the only thing that would happen to an "intent in" argument also (and the same if one would try evaluate an "intent out" variable), at least to begin with (as long as you don't enforce const either).
A side question: I was asking about immutable composite types which are declared with the immutable keyword. Is that equivalent to an instance of a "regular" composite type declared with const?

I think you have a deep misapprehension about const and mutability: const only affects bindings and is completely orthogonal to object mutability. Example:

julia> const a = [1]
1-element Int64 Array:
 1

julia> a = "hello"
ERROR: invalid redefinition of constant a

julia> a
1-element Int64 Array:
 1

julia> a[1] = 2
2

julia> a
1-element Int64 Array:
 2 
 
Making a function parameter const just means you can't reassign the parameter name in the body of the function. Enforcing this is pretty much useless since reassigning the parameter name has no effect on the caller anyway. Making a parameter read-only is about preventing *mutation* – i.e. things of the type `a[1] = 2`, not things of the type `a = "hello"`.

The const declaration is really about letting the compiler generate efficient code.
 That is precisely what I think can be done with providing argument intent; an argument could be treated as a const within the function allthough it's really not.

Constness only helps with globals. It is not at all helpful with locals. There are a few ways in which knowing whether an object is read-only or write-only could help optimization (knowing that a 1-d array won't get resized because it's read-only comes to mind), but there aren't a whole lot of them, and there are other ways to get that information.
 
Although I agree competely on the decision to use call-by-reference model as default, I think it would be really nice if Julia could provide a way to pass-by-value as well (as explicit local copies sometimes can cause confusion).

Again, this would be a massive language complication. The Julian approach is to pick one good way of doing things and stick with it – and make sure it's really great. There are *only* dynamic semantics in the language, but you get static performance most of the time. There is only one dispatch mechanism but it's very powerful. Similarly, there are only reference semantics, no value semantics, but since we support immutable types, you can get the advantages of value semantics without needing to switch mental models based on how a type is declared. And you don't need to have two parallel types systems with incompatible semantics like Java and C# do.
 
I never programmed either Java or C#, but it sure sounds like an laborious approach... Again, I can only say what is the case in Fortran which, being a rather simplistic(in a good sense) language in this respect, doesn't make a programmes life harder by such intricate constructs. When a (dummy) argument is declared with the "value" attribute the compiler simply makes a local copy of the variable to the procedure scope, just as Matlab (and I suppose C) does. The reason I suggested it was that i thought this would be relatively straight forward to implement; it could probably be done in a "macro-style" (not a reference to Julia macros, as I havent studied them yet) where code for copying the actual argument is inserted and the reference pointer changed to the copy instead of the actual argument.

This sounds like you're talking about just calling copy immediately inside of a function. That's a reasonable thing to do and something that a number of Julia functions do in fact do. I'm not sure what "macro style" means here.
 
Perhaps you ask yourself why I'm not just using Fortran. The thing is that I'm also using Matlab a lot, and it is for that part of my work I'm looking into switching to Julia, and since it seems like the language is still in an "early stage" of development (?) I thought that perhaps it would be possible to have some of the features that I find to be very nice about Fortran in Julia... I get that saying no is imporant, but I just wanted to try to clear up what seems to me being a misunderstanding of concepts.

Great to have you trying the language out. In general, I'll just say that Fortran and Julia are very different beasts. It's generally going to be pretty hard to just "move" features from a static, compiled language with zero polymorphism to a language whose core paradigm is dynamic multiple dispatch on generic types – this is about as polymorphic and dynamic as it gets. You're much more likely to "import" features from languages like Matlab, Python or Lisp easily (we have a lot of them already).

Espen Myklebust

unread,
Jun 19, 2013, 2:46:40 PM6/19/13
to julia...@googlegroups.com

On Wednesday, June 19, 2013 6:51:08 PM UTC+2, Stefan Karpinski wrote:
On Wed, Jun 19, 2013 at 10:49 AM, Espen Myklebust <sykl...@gmail.com> wrote:

In a procedure (Fortran has two types; subroutines and functions) you can declare the "intent" of _dummy_ arguments as "in", "out" or "inout". This has *nothing* to do with the _actual_ arguments passed to the procedure in a call. No variables are declared with "intent", only dummy arguments.

I'm not sure what dummy arguments means here. They're never used?
 
With "dummy arguments" it is meant the function argument names which are merely placeholders for the "actual arguments" that is passed to the function when it is called. Maybe there are other words for it but at least there is a definition here. The distinction is very useful when discussing procedures, especially when the properties/attributes of the dymmy arguments may differ from those of the "actual arguments" (such as wrt. read/write access, but the banal example would be that they have different name). In languages that call by value the distinction is trivial since the dummy and actual arguments actually are different objects (due to the copying of the actual argument), and this allows them to be completely different (such as if a type coercion has been performed).
 
 
The Fortran standard does not specify how things should be implemented, but it is my impression that most compilers check that the intents of procedure arguments are obeyed when processing the source code (in the compiler front-end) and it does not necessarily have any effect on the resulting object/machine code. It is there for aiding the programmer convey to the compiler exactly what he intends to do with the passed arguments, but because of this it can help the comipler optimize the code better in which case the resulting code of course may be different than without using it.

In a dynamic language, you cannot generally statically check everything. I think this complicates this issue more than you may be realizing.
 
I'm still not a 100% clear on what is meant by static checking, but as I wrote somewhere it need not be more advanced than how constants are checked (producing only a warning in Julia)
 

People would start getting subtle errors for calling functions on values in some contexts but not others. Seemingly innocuous changes in certain parts of code would suddenly cause problems in apparently unrelated code.
 
In my experience it is precisely the opposite (probably due your understanding of the feature being different from how it works in Fortran). The main reason that I asked if it is possible to declare "intent" in Julia is that it helps me (or rather the compiler) catch errors. It is not uncommon, especially when coming back to a code after some time, that I try to use variables in a manner that is incompatible with how I initially planned the function. When the compiler then complains about this it is usually a good thing as I then avoid possible hard to find errors due to procedure side effects.

I should clarify that what I meant is that people would get subtle *compiler* errors that would be annoying and hard to figure out. The obvious response is that when that happens they would otherwise be getting subtle bugs that would be even harder to figure out. While that's sometimes the case, there are a lot of situations where you know you can appear to violate read/write "rules" but actually be just fine.
 
Ok, then I see what you mean, but I don't agree that this would produce any more strange errors than when assigning a new value to a const
 
 
How would intent annotations interact with multiple dispatch? What if one method of a generic function uses an argument as read-only while another method uses it as write-only? Can you call that function on a read-only value? Can you call it on a write-only value? A read-write value? Does it depend on which method actually gets called? Or does dispatch apply to intent variants? Can you have methods that are distinguishable only by the intent of some argument and which one applies is chosen that way?
 
This is of no concern with the above sketched mechanism since there is no dependence on the actual arguments. Of course a good compiler would complain if you provide a parameter (a Fortran constant) for an argument that the procedure has write access for (intent "out" or "inout"), but I must say I prefer a compiler error over a run-time error.

I can't really tell what the sketched mechanism is, but I'm pretty sure this is not possible to sweep this issue under the carpet like this unless your mechanism is purely for documentation and not checked at all. Example:
The mechanism  I'm referring to is how the "argument intent" works (mainly to prevent one from unintentionally reading or writing to some variable)

abstract Abstract
type Concrete1 <: Abstract field end
type Concrete2 <: Abstract field end

foo(in x::Abstract) = bar(x)
bar(out x::Concrete1) = (x.field = "hello"; return)
bar(in x::Concrete2) = return

Is this an error or not? You certainly can't tell at compile time. It might be possible to make this work, but it's not simple.
This would not be a problem as I understand it (but recall that I havent programmed anything in Julia yet...):
If foo is called by an (actual) argument that has type Concrete1, then the first bar method is called which writes to the "field" field of the (dummy) argument x.
If foo is called by an (actual) argument that has type Concrete2, then the second bar method is called which does nothing and returns nothing.
In the first case the actual argument must allow writing to it though, but that is no different than if the function was declared without the "out" intent, the difference would be that if the compiler knows that a particular actual argument supplied in the call cannot be written to (a const, say) then the compiler could immediately give you a warning/error that your function pressumably will be trying to violate this. They key point of declaring the intent is this: If you have a branch in your function so that in 99% of all calls the dummy argument x will not be (attempted) written to you will never get any warnings/errors when calling the function with a const actual argument, but the one time (of 100) the function tries to write to a const you will get a warning/error (perhaps not yet in Julia, but i guess eventually constants will remain constant?). If the intent was declared as "out" then calling the function with a const would automatically deem the call as illegal.
 
How are immutable types ensured to not mutate? Perhaps the same check(s) could be done for arguments with intent/mode 'in'?

Again, this is a completely different thing: const applies to bindings, not values. Since bindings are limited to a given scope, they're easier to reason about for both compilers and programmers. Currently, only global constness is even paid any attention to – and we don't even enforce it! You can redefine a const global and you'll just get a warning:
 
This could be the only thing that would happen to an "intent in" argument also (and the same if one would try evaluate an "intent out" variable), at least to begin with (as long as you don't enforce const either).
A side question: I was asking about immutable composite types which are declared with the immutable keyword. Is that equivalent to an instance of a "regular" composite type declared with const?

I think you have a deep misapprehension about const and mutability: const only affects bindings and is completely orthogonal to object mutability. Example:

julia> const a = [1]
1-element Int64 Array:
 1

julia> a = "hello"
ERROR: invalid redefinition of constant a

julia> a
1-element Int64 Array:
 1

julia> a[1] = 2
2

julia> a
1-element Int64 Array:
 2 
 
Making a function parameter const just means you can't reassign the parameter name in the body of the function. Enforcing this is pretty much useless since reassigning the parameter name has no effect on the caller anyway. Making a parameter read-only is about preventing *mutation* – i.e. things of the type `a[1] = 2`, not things of the type `a = "hello"`.
 
It was my impression that types in Julia ordinarily are mutable(?), and in that case I don't understand how reassigning a parameter (means the same as dummy argument??) will not affect the caller. Is Julia similar to Python in this respect? Ie. call-by-sharing/call-by-object
If this is the case then I have misunderstood the Julia interpretation of call by reference, but you had an example in an earlier post where reassigning a const produced a warning, so there must be some immutability connected to a const..?
 

The const declaration is really about letting the compiler generate efficient code.
 That is precisely what I think can be done with providing argument intent; an argument could be treated as a const within the function allthough it's really not.

Constness only helps with globals. It is not at all helpful with locals. There are a few ways in which knowing whether an object is read-only or write-only could help optimization (knowing that a 1-d array won't get resized because it's read-only comes to mind), but there aren't a whole lot of them, and there are other ways to get that information.
Sure there are other ways, but will they be more efficient than declaring the intent ?
 
Although I agree competely on the decision to use call-by-reference model as default, I think it would be really nice if Julia could provide a way to pass-by-value as well (as explicit local copies sometimes can cause confusion).

Again, this would be a massive language complication. The Julian approach is to pick one good way of doing things and stick with it – and make sure it's really great. There are *only* dynamic semantics in the language, but you get static performance most of the time. There is only one dispatch mechanism but it's very powerful. Similarly, there are only reference semantics, no value semantics, but since we support immutable types, you can get the advantages of value semantics without needing to switch mental models based on how a type is declared. And you don't need to have two parallel types systems with incompatible semantics like Java and C# do.
 
I never programmed either Java or C#, but it sure sounds like an laborious approach... Again, I can only say what is the case in Fortran which, being a rather simplistic(in a good sense) language in this respect, doesn't make a programmes life harder by such intricate constructs. When a (dummy) argument is declared with the "value" attribute the compiler simply makes a local copy of the variable to the procedure scope, just as Matlab (and I suppose C) does. The reason I suggested it was that i thought this would be relatively straight forward to implement; it could probably be done in a "macro-style" (not a reference to Julia macros, as I havent studied them yet) where code for copying the actual argument is inserted and the reference pointer changed to the copy instead of the actual argument.

This sounds like you're talking about just calling copy immediately inside of a function. That's a reasonable thing to do and something that a number of Julia functions do in fact do. I'm not sure what "macro style" means here.
Yes.
The macro-style would be that the code to perform exactly such a copy immediately after the call is inserted in the beginning of the function. This should of course be done by the compiler (viz. not by a "macro") but as I understood you that would be difficult.
 
Perhaps you ask yourself why I'm not just using Fortran. The thing is that I'm also using Matlab a lot, and it is for that part of my work I'm looking into switching to Julia, and since it seems like the language is still in an "early stage" of development (?) I thought that perhaps it would be possible to have some of the features that I find to be very nice about Fortran in Julia... I get that saying no is imporant, but I just wanted to try to clear up what seems to me being a misunderstanding of concepts.

Great to have you trying the language out. In general, I'll just say that Fortran and Julia are very different beasts. It's generally going to be pretty hard to just "move" features from a static, compiled language with zero polymorphism to a language whose core paradigm is dynamic multiple dispatch on generic types – this is about as polymorphic and dynamic as it gets. You're much more likely to "import" features from languages like Matlab, Python or Lisp easily (we have a lot of them already).
I hope Fortran and Julia can be complementary for numerical computations, with their strengths and weaknesses. But my impression was that Julia will be aimed at much the area where Fortran excels, and so I would think that looking to Fortran would be perhaps just as valuable as lower performing languages. Obviously the paradigms (static/dynamic) are very different, but their goal of being the fastest in their respective categories is the same.
PS: If you think that Fortran doesn't have polymorphism (and probably OOP features) I encourage you to take a look at a book on Fortran 2003 or newer. Alternatively, you can see which features have been implemnted in GCC gfortran here.

Stefan Karpinski

unread,
Jun 19, 2013, 3:22:01 PM6/19/13
to Julia Users
Julia is pass-by-sharing like Python, not what wikipedia calls pass-by-reference (although that definition is far from universally accepted, so I wasn't clear on what you meant by it). To be clear, in Julia, a function call cannot change what value a variable in the caller is bound to but you can change the *value* that a variable is bound to as long as that value is mutable. You seem, however, to be pretty confused about the difference between variable bindings and values – probably because they are significantly conflated in most static languages. Constness applies to variables: const variables cannot be rebound (without a warning), whereas other variables can. Mutability applies to values: immutable values cannot be modified, whereas mutable ones can. These are completely orthogonal concepts – you can have a const variable bound to a mutable value or a non-const variable bound to an immutable value, or any other combination of constness and (im)mutability. Your proposal is fundamentally incoherent because it applies a property of values – i.e. mutability vs. immutability – to bindings, confusing it with constness, which is actually a property of bindings.

Espen Myklebust

unread,
Jun 19, 2013, 4:06:41 PM6/19/13
to julia...@googlegroups.com
In that case I urge you or any other of the people that write the documentation to specify more clearly what is meant in the documentation by:

       Values are passed and assigned by reference. If a function modifies an array, the changes will be visible in the caller.

Relying on other people having the same understanding of this term can evidently cause some confusion. If the above line from the documentation is correct though, my previous points must be valid for arrays at least..?

 

Stefan Karpinski

unread,
Jun 19, 2013, 4:12:01 PM6/19/13
to Julia Users
Arrays are mutable values – you can modify the contents of an array passed to a function, but not which array a variable in the caller is bound to. We should definitely clarify this in the manual since it seems to be a significant point of confusion for people coming from non-dynamic languages. That sentence is actually mostly targeted at people coming from Matlab, in which you cannot modify the caller's array value by passing it to a function.

Stefan Karpinski

unread,
Jun 19, 2013, 4:14:49 PM6/19/13
to Julia Users

Espen Myklebust

unread,
Jun 19, 2013, 6:29:43 PM6/19/13
to julia...@googlegroups.com
So now that we hopefully talk the same language; would it not be a good thing to be able to decalare intent at least for arrays and other types where this can happen?
I think the mere existence of such a syntax would be a very effective means for signaling that this kind of behavior is possible, especially for converted Matlab users that often do not have a thorough background in CS to really comprehend this somewhat fine point.


And as you said earlier, it could have a performance benefit for arrays also :)

Stefan Karpinski

unread,
Jun 19, 2013, 7:00:43 PM6/19/13
to julia...@googlegroups.com
We use a trailing bang "!" as a purely conventional way of indicating that a function may mutate one of its arguments. There's an issue somewhere about being able to indicate that a function is pure.

Stefan Karpinski

unread,
Jun 19, 2013, 7:09:12 PM6/19/13
to julia...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages