My wishlist for the next version of Julia

There is potentially a big difference between Matlab’s [a,b] = fm(...) and Julia’s a,b = fj(...).

In Matlab it’s possible to have internal conditional code to not compute b if the function is called as a = fm(...). This is not possible in Julia.

5 Likes

Note that & is a bitwise and operator. What is evaluated in 2 > 1 & 4 > 3 first is 1 & 4:

julia> 1 & 4
0

But note the type of the result

julia> typeof(1 & 4)
Int64

What is evaluated subsequently is

julia> 2 > 0 > 3
false
5 Likes

For those who wonder how this works, you have a magical variable nargout in your function, which you can check to see how many outputs the caller will receive, like this:

Similarly you have a nargin variable available for the input arguments, which can be used to assign default values to left out arguments, or other transformations of the arguments, e.g.

I’m particularly happy about having left that language feature behind me.

11 Likes

Oh no, let’s not go there!

2 Likes

my limited explore of MATLAB has told me that every function has 100 lines preamble to check nargin and nargout which is just… why :frowning:

10 Likes

An analogous behavior (conditional computation of outputs) can be achieved in various ways:

  1. Simply give the function different names for different numbers of outputs.
  2. Return an object that computes the additional outputs as requested, for example by returning an iterator. e.g. Julia’s lu(A) function for LU factorization returns a factorization object F, which can either be used as-is to solve linear systems via x = F \ b or can be used to compute factors F.L, F.U as desired (which are otherwise not computed explicitly — this is accomplished by overloading getproperty in Julia), and which is also iterable so you can do L, U = lu(a) or L, U = F, for example.
  3. In-place functions, conventionally written in Julia as f!(x,y). If you don’t want a particular output, either don’t pass it — call f!(x) and dispatch to a different method — or pass some sentinel value (e.g. nothing).

Option 2 is the closest analogue of the Matlab nargout, and syntactically looks very similar to the user if an iterable object is returned.

15 Likes

I don’t really think this is that great of syntax, but I had a bit of fun making a macro to do this with a slight change and a bit of Julia flavour.

using MacroTools: @capture
using ExprTools: splitdef, combinedef

macro m(ex)
    @capture(ex, [args__] = fdef_) || error("Malformed input syntax")
    d = splitdef(fdef)
    d[:body] = :($(d[:body]); (; $(args...),))
    esc(combinedef(d))
end

Here it is in action:

julia> @m [m, s] = function stat(x)
           n = length(x);
           m = sum(x)/n;
           s = sqrt(sum((x .- m).^2/n));
       end
stat (generic function with 1 method)

julia> stat(rand(100))
(m = 0.46880423584214137, s = 0.2769434039119943)

One thing that’s kinda nice is that this returns the outputs as a NamedTuple, but if you prefer a regular Tuple, you could instead do

macro m(ex)
    @capture(ex, [args__] = fdef_) || error("Malformed input syntax")
    d = splitdef(fdef)
    d[:body] = :($(d[:body]); ($(args...),))
    esc(combinedef(d))
end
16 Likes

I guess the important thing to highlight is that Julia is such a wonderfully hackable language with very powerful metaprogramming, that it’s actually quite easy to mould the language syntax to your needs.

4 Likes

JuliaLang and @Mason are an impressive team.

3 Likes

As of MATLAB 2020, there’s a keyword arguments which lets you define defaults, assertations etc. It’s pretty good (for MATLAB) but it’s nowhere near as nice as just doing this in the signature.

(And MATLAB 2021a introduced a keyword=argument syntax as a parallel to the existing (and awful) 'keyword', argument)

2 Likes

I meant if there were any differences besides the parenthesization.

&& is a shortcuting operator, which means the second term isn’t evaluated if the first one is false, whereas & evaluates everything:

julia> true && (println("a"); true)
a
true

julia> false && (println("a"); true)
false

julia> false & (println("a"); true)
a
false

the short-cutting behaviour doesn’t work for .&& though, it behaves like .& but with the nicer precedence: for the short-circuit with .&&, there must be a broadcasted function, see this answer and the 2

next ones

julia> [false] .&& [(println("a"); true)]
a
1-element BitVector:
 0

julia> [false, true] .&& println.(1:2)
2
2-element Vector{Union{Nothing, Bool}}:
 false
      nothing

&& can have non-booleans in the last term:

julia> true && 2
2

julia> false && 2
false

julia> 2 && true
ERROR: TypeError: non-boolean (Int64) used in boolean context
Stacktrace:
 [1] top-level scope
   @ REPL[14]:1

while & is a bitwise operation:

julia> 3 & true
1

julia> 2 & true
0

https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation

3 Likes

Ah ok. This is what I was asking. Thanks

1 Like

correction, it’s not really identical, this wouldn’t work with &:

julia> rand(Bool, 5) .&& "abc"
5-element Vector{Any}:
 false
 false
      "abc"
      "abc"
 false
2 Likes

Mmm. Are you sure it is not short-circuiting somehow?

Although I am not sure how “short-circuit” would work in broadcasting

Yeah, I think even MATLAB wants you to be using the Julia syntax for this now, which is why it was added.

1 Like

Haha I remember writing a MatLab function to automatically generate the text of the most common nargin and nargout code based on a function signature (also in text), which I would then just paste into the top of my new function. Oh unhappy days.

1 Like

Hi, @leon! I just wanted to say hello and thank you for the suggestions and say that I hope the barrage of replies doesn’t feel overwhelming or unfriendly. People are just excited about programming languages here (especially Julia, of course), and being helpful. It seems like there are ways to do all these things, even if they’re not exactly like they are done in Matlab. Please don’t hesitate to ask about any other things that feel more awkward than they should—there may already be a way to express it better… or it may be an opportunity for us to improve the language and make something awkward a little easier, which is always exciting!

32 Likes

Many thanks for the very kind reply, Stefan! No worries, I find most of the replies to be very helpful. It’s also ok to push back on some of my suggestions. I now come to appreciate the Julia way of defining a function, for example.

As a newbie, I start to love Julia a lot. Therefore, I just hope Julia can be improved in certain ways.

I got lots of help from lots of people in this community recently and I’m wholeheartedly grateful. Thank you so much, Everyone!

24 Likes

Just to play devil’s advocate, you can do essentially the same in Julia:

function f(x, y)

    A = stuff
    lines
    of
    code
    B = other stuff
    more
    code
    return (A, B)

end

But perhaps requiring the “return” statement (optional return keyword) encourages A and B to be computed close to or immediately before the return statement.

1 Like