Skip to content

Automatic broadcasting syntax f.(A) is inconsistent #22501

@ZacCranko

Description

@ZacCranko

I have been out of the loop for a little bit and so I realise I am a little bit late to the discussion #15032, but having seen the f.(A) syntax at JuliaCon it strikes me as inconcistent. I'll try to explain why.

The infix notation A .+ B has the . prefixing the function symbol +, so maybe you are saying to yourself "this is not a problem, infix notation is just somehow special" and lines of code such as

 A .+ B .* sin.(C)

are really just fine and all is well in the universe... until you realise that these infix functions can also be written as prefixes, e.g.:

(+)(x::T, y::T) where {T<:BitInteger} = add_int(x, y)

So now what should be the correct way to broadcast +? Is it (+).(x, y) = broadcast(+, x, y),
or is it (.+)(x, y) = broadcast(+, x, y)? Currently both of these work (+.(x, y) does not, cf. #22498).

Hopefully by now I have convinced you of the problem. Next is to convince you that the solution to this problem is to switch to .f(A) and not to change the broadcast infix operators to +..

Dot postfix on operators: A +. B

Pros:

  • Consistent with function broadcasting f.(A)
  • Operations like x*.abs.(y) are easier to read (sorta?)
  • Inconsistent with many other popular programming languages whose names I don't need to mention here (Julian recalcitrance)

Cons:

  • Undefined (unattractive?) for the in-place operations: Should it be i +.= 1 or i +=. 1? Maybe both are undesirable.
  • .(A) is kind of meaningless as an object on its own, cf. .f with respect to .+
  • A *. 2 will be confused with A * 0.2. My reply: "The same kind of parsing issues exist as with 2. * A, either way you have to declare some things illegal"

Dot prefix everywhere: .f(A)

Pros:

  • Consistency with infix operators
  • Reads nicely for the the in-place operations i .+= 1.
  • As pointed out by @JeffBezanson, . has the nice interpretation as a function .(f) = (args...) -> broadcast(f, args...)
  • Consistent with many other popular programming languages

Cons:

  • Confusing to parse visually in expressions like x.*.abs(y). My reply: "vectorised expressions are always going to be ugly and hard to read, wachagonnado".

Personally I prefer the second solution, but I think either would be superior to current situation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    won't changeIndicates that work won't continue on an issue or pull request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions