I see that custom infix operators are a long-standingobject to discussion, and I like to ask if there is a way today, how I can alias ∘ to >>
As an explanation, my VSCode wont tab complete the \circ and I am already used to >> from F#
But I am unsure if I can make such an alias at all currently, and if so, if its possible to define it as infix operator.
The biggest reason you couldn’t is both are already used for important functions, function composition and bitshifting respectively, so you’d break something if you could reassign one name to another, which you can’t for constants.
Let’s instead assume you’re talking about an operator that nobody uses; you can make a separate variant of any accepted infix operator by suffixing it like >>̂ (type >>\hat<tab> in REPL), but you cannot define arbitrary text as infix operators. The reason you shouldn’t do that is infix operators have fixed precedence according to their parser, and suffixed variants share precedence with their original. ∘ has different precedence from >>, so you don’t want >>̂ to do what ∘ does.
Example of operator aliasing:
julia> const >>̂ = ∘
∘ (generic function with 3 methods)
julia> >>̂ # verify successful aliasing
∘ (generic function with 3 methods)
julia> (==(6)∘length)("apple1")
true
julia> (==(6)>>̂length)("apple1")
true
But the precedence remains different, so assuming the alias is fully equivalent is incorrect and will cause bugs in operator chains.
This reads like its mostly a chore, and really not a straight forward process.
So I am mostly limited to use symbols, that are either not used at all, or those who have the same precedence level of the original symbol.
I am really not interested in the bitshift operator, but I guess you would still discourage me to replace it. It seems like jumping through hoops, just to get normal composition/piping running.
You’re right, by “reassign” I was assuming that the exported names >>, ∘ were already used. But I suppose it’s very possible to not need both function composition and bitshifting, so shadowing one of the exported names is more likely. Was trying to think of a way to distinguish if a name was created in a module or exported from another one, but I can’t recall one.maybe asymbol in names(amodule; all=true).
From the old Julia parser, one can look up new, unused operators recgonized by Julia with a given level of precendence. In your case, here are all the operators with the same precedence as \circ:
You can pick any one of these and use as a drop-in replacement for \circ, e.g., \odot:
julia> const ⊙ = ∘
Admmittedly, the list is a bit short on ASCII symbols, so if tab replacement of symbols is generally non-functional in your VSCode setup, then you’re out of luck.
Just a remark: >> in F# is forward, i.e., left-to-right, composition, whereas ∘ adheres to the mathematical convention of right-to-left. Guess that making it an alias would be very confusing at best.
(It’s fine to define it accordingly though, e.g., >>(funs...) = ∘(reverse(funs)...), but maybe using another symbol due to shadowing Base.:>> and different precedence as mentioned by others already).
To me, bit shifting sounds like something imperative, and that I am not quite so fond of.
@HanD Oh, thanks for making the effort to present that so orderly to me.
I generally like to avoid tab completions.
Not because of myself, first and foremost, but because I like to have a symbol that I can show to colleagues, without getting looked at from the corner of the eye, with a raised eyebrow, or two.
@bertschi Thanks - yeah, and F# is using << instead of ∘.
They generally recommend |> and >>, since this is more how you read it.
I ultimately found (more than) what I wanted in this suggestion, and really hope it gets accepted.
What does that even mean? How can 1 pure binary operation distinguish an imperative or functional paradigm? Looking it up, F# has bitshifts >>> and <<<.
F# is a multi paradigm language, and I consider everything imperative, that essentially mutates data. And it is, as far as I can tell, mainly used with low level languages?
I know very little on the topic of low level operations.
I am a newbie to programming in general.
And no, I don’t consider multiplying integer mutating state.
I simply thought, shifting bits meant to actually change them in memory.
It seems like this is not the case.