What's your favorite syntactical sugar in Julia

I like the @view macro (it’s super handy!) and the broadcasting with .

julia> A = rand(5, 5)
5×5 Matrix{Float64}:
 0.707239  0.440889  0.958134  0.783449   0.913452
 0.741968  0.276487  0.489972  0.0194192  0.453019
 0.318276  0.318808  0.156329  0.268038   0.223835
 0.915922  0.743359  0.564748  0.60688    0.94491
 0.344369  0.136049  0.539166  0.962701   0.831359

julia> subA = @view A[2:4, 2:4]
3×3 view(::Matrix{Float64}, 2:4, 2:4) with eltype Float64:
 0.276487  0.489972  0.0194192
 0.318808  0.156329  0.268038
 0.743359  0.564748  0.60688

julia> subA .= 0
3×3 view(::Matrix{Float64}, 2:4, 2:4) with eltype Float64:
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

julia> 
2 Likes

One of my biggest pain points in Julia is that [...] makes a copy.

Using the macro in nested expressions needs parentheses which makes it not as quick to type:

julia> .+(x[1:3], x[2:4])
3-element Vector{Float64}:
 -0.7509311698949941
  1.709855739076295
  0.7021749402293793

julia> .+(@view x[1:3], @view x[2:4])
ERROR: LoadError: ArgumentError: Invalid use of @view macro: argument must be a reference expression A[...].
Stacktrace:
 [1] var"@view"(__source__::LineNumberNode, __module__::Module, ex::Any)
   @ Base ./views.jl:138
in expression starting at REPL[11]:1

julia> .+(@view(x[1:3]), @view(x[2:4]))
3-element Vector{Float64}:
 -0.7509311698949941
  1.709855739076295
  0.7021749402293793

julia> .+(@view(x[1:3]), @view(x[2:4]))

I wonder actually, why this does not work. The @. propagates fully into the whole call, @view does not:

julia> @view x[1:3] .+ x[1:4]
ERROR: LoadError: ArgumentError: Invalid use of @view macro: argument must be a reference expression A[...].
Stacktrace:
 [1] var"@view"(__source__::LineNumberNode, __module__::Module, ex::Any)
   @ Base ./views.jl:138
in expression starting at REPL[13]:1

Try @views instead of @view. That should apply to the whole expression. You can even apply it to a block, such as an entire function.

3 Likes

Isn’t it the case for @views?

2 Likes

I’m writing this to synthesize what I learnt thanks to you guys (and the Julia source code & docs). My understanding is that:

@view expects an array-indexing expression => you must give it something like x[1:3] or x[:] (throws an error otherwise)

@views expects “any” expression and transform array-slicing operations into views => cf. below (have been playing with @views)

julia> @views 1+2+3; "This is noise"
"This is noise"

julia> @views 1+2+3; "This is noise"; A
3×3 Matrix{Float64}:
 1.0  1.0  1.0
 2.0  2.0  2.0
 3.0  3.0  3.0

julia> @views 1+2+3; "This is noise"; A[:]
9-element Vector{Float64}:
 1.0
 2.0
 3.0
 1.0
 2.0
 3.0
 1.0
 2.0
 3.0

julia> A
3×3 Matrix{Float64}:
 1.0  1.0  1.0
 2.0  2.0  2.0
 3.0  3.0  3.0

and finally (as @DNF and @rafael.guerra suggested), voilà

julia> @views .+(x[1:3], x[2:4])
3-element Vector{Float64}:
 0.6605174669013307
 0.8487232659913083
 1.2442778601207747

The @views stops at the ;. Add parentheses, or begin/end as mentioned earlier, if you want it to apply across the ;

julia> @macroexpand ( @views 1+2; a[1] )
quote
    1 + 2
    #= REPL[8]:1 =#
    a[1]
end

julia> @macroexpand @views ( 1+2; a[1] )
quote
    1 + 2
    #= REPL[9]:1 =#
    (Base.maybeview)(a, 1)
end

julia> @macroexpand @views begin 1+2; a[1]; end
quote
    #= REPL[11]:1 =#
    1 + 2
    #= REPL[11]:1 =#
    (Base.maybeview)(a, 1)
end
3 Likes

thank you for the clarification :+1:t3: