David Kubecka
09/12/2024, 11:50 AMfoo
is declared ambiguous, since "hello"
may work both as String
or Any
context parameter.
> context(Any) fun foo() {}
> context(String) fun foo() {}
>
> fun test() = with("hello") {
> foo()
> }
>
> The reasoning for this particular rule is that, since contexts are implicit, there is no way for the user to resolve to the other function if required. This implicitness also means that it's harder to figure out which overload is called from the program code -- once again, there's no value you can easily point to. In contrast, in the case of an explicit parameter, you can always use f("hello" as Any)
to force using (Any) -> R
over (String) -> R
.
Why the same reasoning about explicit casting can't be used here?
fun test() = with("hello" as Any) {
foo()
}
Youssef Shoaib [MOD]
09/12/2024, 11:52 AMAlejandro Serrano.Mena
09/12/2024, 11:55 AMString
in context -> both foo
apply, so we get an ambiguity error
• Any
in context -> only the one with context(Any)
applies, so it should be the chosen oneYoussef Shoaib [MOD]
09/12/2024, 11:58 AMString
in context case shouldn't be ambiguous and should instead resolve to the String
version of foo
David Kubecka
09/12/2024, 11:58 AMphldavies
09/12/2024, 12:48 PMmyReceiver.myMethod(context(a="hello" as Any), otherParam)
(terribel example syntax)
scala has the implicit parameter list that can be explicitly specified if/as requried.Youssef Shoaib [MOD]
09/12/2024, 1:05 PMcontext
function that's basically a multi-with, so context("hello" as Any) { myReceiver.myMethod(otherParam) }
is somewhat reasonable.Alejandro Serrano.Mena
09/12/2024, 4:10 PMphldavies
09/12/2024, 4:23 PMcontext(_: Any) fun foo() {}
context(_: String) fun foo() {}
fun test() = context("hello") { foo() }
but with the following it would be happy (and call the first foo
):
context(_: Any) fun foo() {}
context(_: String) fun foo() {}
fun test() = context("hello" as Any) { foo() }
in which case, there's no way to call the second foo
- it would be entirely reasonable to resolve the function with more specific matching context types, no?Youssef Shoaib [MOD]
09/12/2024, 4:25 PMfun Any.foo() {}
fun String.foo() {}
fun test() = with("hello") { foo() }
Alejandro Serrano.Mena
09/12/2024, 4:29 PMString
(and thus Any
) in the context, so there's an ambiguity, whereas in the second case you only have Any
, so there's no ambiguity
@Youssef Shoaib [MOD] yeah, the language is not entirely uniform in that respect. But I think that adding more implicitness to the game is a recipe for developers to be confused whenever something doesn't resolve as it should.
Note also the very different ways in which receivers and context parameters are resolved:
• for the receiver we actually look inside the member scope of each implicit receiver, which means that foo
"lives" inside of String
, so it's chosen without ever going to the parent Any
• for the context parameters the functions are actually top-level, both are found, and then we filter out by available context valuesphldavies
09/12/2024, 4:33 PMString
and Any
being available is one the developer will be unable to overcome (as they aren't able to tell the compiler to treat the String
in context explicitly as String
and not as Any
in order to remove the ambiguity. As such, with both context(String) fun foo()
and context(Any) fun foo()
in scope it is impossible to invoke context(String) fun foo()
phldavies
09/12/2024, 5:04 PMcontext(BufferedWriter) log(String)
over context(Writer) log(String)
which is just as applicableAlejandro Serrano.Mena
09/13/2024, 7:11 AM