:speaker:Hello everyone!, There is currently some...
# arrow
r
🔈Hello everyone!, There is currently some internal discussions as to what to call the monad operator in Arrow for the 1.0 series. We plan on introducing a single version for this going forward in 0.12.0 and would love your feedback as to what style you prefer. We would love your help in helping us decide by voting in one of the following options: 1️⃣ bind
Copy code
either {
  val a = funThatReturnsEither().bind()
  val b = eitherValue.bind() 
}
2️⃣ invoke
Copy code
either {
  val a = funThatReturnsEither().invoke() //explicit
  val b = funThatReturnsEither()()  //implicit 
  val c = eitherValue()
}
3️⃣ not
Copy code
either {
  val a = !funThatReturnsEither()
  val b = !eitherValue
}
4️⃣ other and opinions: (reply in a thread to this message)
3️⃣ 21
1️⃣ 47
2️⃣ 8
4️⃣ 1
t
Not operator had some drawbacks in the past isn't?
c
I'm a bit worried that the
!
notation might hurt readability. I liked the
component1
but you explained why that's not possible, too bad.
bind
is at least very easy to understand, but it's also not ‘beautiful'...
r
the drawback is that it can be confused in the case of something like
Either<Error, Boolean>
since you’re not negating the boolean value in
!eitherValueContainingBoolean
instead you are obtaining the boolean value you i’d require
!!
to negate.
My personal preference is
not
because the edge case is rarely seen and
!
makes me easily see where all effects are firing without the
bind
boilerplate but I agree that bind is more explicit. My concern with bind is that inside a computation block is gonna show up in pretty much every line and adds quite a bit of noise to what the code is actually doing.
👍 3
s
Is
val x by myFunction()
still an option? (the for comprehension plug in syntax)
r
The
by
option has two issues. delegation support for suspension and it requires always to define a new
val
and name it, even when you don’t care about the result.
☝️ 1
j
yes you don't always want to assign to a val just fire the effect
s
You cannot do
val _ by something()
r
Also makes expressions like this no longer possible because of the declaration requirement:
Copy code
!f + !g
s
I have tried not internally, my teammates didn’t like it. Sometimes methods return Boolean, (because we make tiny methods, and big conditions ends up as a method) and they become unsure what is going on, as they already struggle in understanding fp in general.
👍 2
a
just want to point out that the delegation way seems to be something common now in Compose
j
It is but I suspect it's because the pattern is to assign the result of a computation to consume it as uiState so the big majority of the time that requires a variable
a
yes, that’s why I suggest having that + another like invoke/bind
so if you want to inline, you can with those, otherwise you can use the delegation
r
by
could be added easily once suspension support is working on main Kotlin and not just IR on delegated suspended properties https://youtrack.jetbrains.com/issue/KT-20414
👌 1
c
Would there be a way to add a plugin in IntelliJ that displays
bind
as something else, to create a syntax that doesn't already exist? Even if it's rare that
!
is actually used for negation, it's still a syntax that's deeply linked with it, and you can't know if it's negation or
bind
without reading very deeply into the code (especially if you have an effect that returns a boolean) One solution could be to have an IDEA plugin that displays a different unicode character that doesn't exist in the Kotlin language for this specific character, so you would type
!
but it would show up as something else (obviously there needs to be an option to disable it if you prefer to read the real code). In the same way that IntelliJ can ‘render' documentation, or simplify functions by putting them in a single line, you would see something like :
Copy code
either {
  val a = ▷funThatReturnsEither()
  ▷a + ▷Right(5)
}
The code would use !, but if the IDE could put this as a ‘hint', there would never be any ambiguity (since the IDE knows without a doubt which it is)
r
yes down the road once Kotlin supports offitially compiler plugins so we don’t actually have to write an IDEA plugin. A custom IDEA plugin requires distribution and manual installation from a marketplace which is not something Arrow wants to impose in users.
these kinds of features like hidding syntax or things as we discussed before like union types can be brought like that with arrow meta but we are gonna wait until the Kotlin IDEA plugin is aware of compiler plugins instead of rolling our own IDEA separate features that require manual install.
c
In general, I would really like if Kotlin was more open to unicode, like Julia is (for example, you can write
f1 ◯ f2
for composition, it really helps readability when it's not overused).
Oh, that makes a lot of sense then! Thanks for the information
r
only with backticks 🙂
Copy code
fun <A> A.`◯`(other: A): A = TODO()
t
My opinion: • The
!
notation for monad operators looks very alien to the rest of the language. It used to be strictly negation and anyone new to the codebase, Arrow or both would likely be lost on what it means. I think the
!
has a really strong meaning that will just cause confusion. • The
invoke
,
()
notation looks best, because it indicates to me that some sort of processing will be happening, a function invocation. A monad bound to the context in this case. • The
bind()
notation is meh, but still better than negation.
👍 5
r
@tginiotis invoke was or maybe it’s still my favorite but users seem to dislike that in cases where you are going to invoke a function that say returns
Either
and you are in an
either
block then you have these double invokes
Copy code
funThatReturnsEither()()
t
I wonder why they would dislike that though, it seems easy to follow that to bind a result of a HOF you just have to call invoke twice. Otherwise, double invokes do look uncommon (but not as alien like negation on non-booleans), but can be reasoned about off the bat that some processing is happening twice
👍 2
r
I agree
t
oh, not a HOF, but a monad returning function needs to be invoked twice. Still pretty distinct
a
IMO 1.
bind
explicitly implies that you’re “extracting” the value from the monad so you can operate over it. It makes it easier for non-FP developers to follow your code (maybe you don’t understand how, but you know that
Either<A,B>.bind()
gives you a
B
) 2.
invoke
has a similar effect as
bind
, the problem would be, again, for non-FP devs to understand what “executing a monad is”. Also, non-FP devs are not so used to see
function()()
3. I really like
!
. It’s simple & concise. Major drawback, as you mention, is the usecase with booleans. Plus maybe readability issues? Is it feasible to have, for example,
bind
as the “main” operator and both
invoke
and
not
as inline functions that just invoke
bind
?
s
I would also add that IMO is better to pick 1 option of the suggested (whichever might be) and use that one..... IMO that would be easier for beginners and eliminates discussions on which one should I use It also means you only need to learn one syntax, so by understanding one you can read any code
👍 2
j
That is the rationale of this poll, afaik
👍 1
r
Let’s wait until tomorrow but as Jorge said the idea is to keep a single operator based on what gets most votes here. Thanks everyone for sharing your thoughts and participating 🙏
🙏 1
1
c
I'm surprised that there are so few votes for invoke, especially since it's part of the Kotlin language. I really dislike ! since: • mentally I say "not" every time •
!!
to negate a boolean •
!!
is already used in Kotlin to convert to a non-nullable type
👍 4
a
I guess invoke might be more relatable to function or constructor invocations and not that much for this
s
The reasoning behind my vote for
bind()
was to keep the method explicit for now, knowing that syntactic sugar may be available as compiler plugins in the future.
👍 4