How weird is this syntax for context parameters? ...
# language-evolution
a
How weird is this syntax for context parameters? I was playing with the kotlin sytnax in my head, and I came about the extension function syntax something like
Copy code
fun Human.canSing() : Boolean = true
And it occurred to me that, the same function should be able to be written as follows
Copy code
fun (Human).canSing() : Boolean = true
Why the extra parantheses you ask?? Bear with me. But for now, the second syntax and the first one should resolved to exactly the same thing just like how expressions would be treated
Copy code
val x = 3 + 4 // same as val x = (3 + 4)
Wether you put parentheses or not is up to you. This then propelled me into context parameters, With this kind of syntax, we open room to a new syntax one that supports context parameters (or Intersection Types as I like to delude myself by hopping that user defined intersection types will be coming to kotlin). The new syntax would then look like this
Copy code
fun (Human & Cat & Dog).canSing() : Boolean {
   // code goes here
}
I don't know about you, bout I prefer this syntax over the one proposed earlier with
context(Human,Cat,Dog)
At the same time, this syntax also open doors for the long awaited union types
Copy code
fun (Human | Cat | Dog).canSing() : Boolean {

}
Ofcourse, I do not know how much work is going to have to into the compiler to achieve this (I am not a compiler expert). But this syntax looks almost native to kotlin (atleast for me) Thoughts????
j
IMO using
&
or
|
is very problematic because it implies a single instance of the intersection/union type, which is not what context parameters are (they are several distinct instances, each of their own types). It's way more natural to me to use commas to separate these parameters, just like in other parameter lists (regular function parameters, lambda parameters, etc.).
☝️ 3
1
A second problem is that the receiver type still exists, and there is only one. Context parameters exist in addition to the receiver. The receiver is used in receiver position at the call site (
receiver.canSing()
), while context parameters are implicitly passed from the current scope. The proposed syntax is explicitly designed to make the declaration site look like the call site (contexts come "from above"), just like for the receiver (which is the thing before the dot):
Copy code
context(cat: Cat, dog: Dog)
fun Human.canSing(): Boolean = ...

fun main() {
    with(Cat(), Dog()) {
        Human().canSing()
    }
}
1
e
Copy code
class A {
    fun B.foo() { println("A.B") }
}
class B {
    fun A.foo() { println("B.A") }
}
yep. the explicit receiver in the current language (even without context receivers parameters) can disambiguate what would otherwise be ambiguous if they were all implicit
Copy code
with(A()) { B().foo() } // A.B
with(B()) { A().foo() } // B.A
a
I get your point @Joffrey
j
Parentheses around types are reserved for tuples, so the syntax can't really be used for other features. I'm not sure if union types will be available for anything other than return types. If they work for extension functions, the existing
where
syntax will be used most likely.
s
I'm worried about what kind of a creature counts as n intersection of a dog, a cat and a human 😅
😂 3
j
Nothing
😆 2