How can I trust a compiler that specifies it is okay to call one of two ambiguous overloads?

203 views
Skip to first unread message

Shelby

unread,
Sep 20, 2013, 10:56:07 AM9/20/13
to scala-...@googlegroups.com

Som Snytt

unread,
Sep 20, 2013, 12:57:42 PM9/20/13
to Shelby, scala-debate
Maybe because it's not ambiguous as nicely specified, and overloading is evil.

Your trust issues aside, perhaps you're asking for a switch that disables overload resolution in the presence of default args.

`import scala.language.noob` or similar as a way to enhance error messages or provide a subset of features that is still correct scala.




On Fri, Sep 20, 2013 at 7:56 AM, Shelby <she...@coolpage.com> wrote:

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-debate...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Russ Paielli

unread,
Sep 20, 2013, 2:02:48 PM9/20/13
to Shelby, scala-debate
I am surprised that that is allowed. It means that when I see a function definition that matches the signature of the call, I can't be sure it is the one that will be called. That can't be good for readability.


On Fri, Sep 20, 2013 at 7:56 AM, Shelby <she...@coolpage.com> wrote:

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-debate...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Shelby

unread,
Sep 20, 2013, 2:04:38 PM9/20/13
to scala-...@googlegroups.com, Shelby
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing any way and not uni-typing (e.g. dynamic).

Because humans are fallible and that is why the compiler checks our assumptions, based on what we wrote in code, not only what our mind thought the hundreds of pages of the specification said.

√iktor Ҡlang

unread,
Sep 20, 2013, 4:01:09 PM9/20/13
to Som Snytt, Shelby, scala-debate

That's a bit condecending. Please maintain a good tone.

Cheers,
V

Rex Kerr

unread,
Sep 20, 2013, 5:12:06 PM9/20/13
to Shelby, scala-debate
On Fri, Sep 20, 2013 at 11:04 AM, Shelby <she...@coolpage.com> wrote:
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing

I think you're underestimating the amount of ambiguity to be had.

def foo(a: Int)(implicit b: Int): Array[Int] = Array(b, a)
implicit val x = 5
val bar = foo(3)(1)

What is the type of bar?  What is the result?  Is it 3 or Array(1,3)?

It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

This is one of the taxes you have to pay to gain the expressive power of Scala.

Making a rule that foo(x) means foo(x), not foo(x, defaultY) seems fine to me.  You do need to know it, and you can if you choose use it to obfuscate your code, but in any reasonably constructed and properly documented code it shouldn't be an issue at all because (1) foo(x) and foo(x, y = Y) are next to each other in the code, and (2) they're also next to each other in the Scaladoc.

If you're going to allow overloads at all, that is.  (If you allow overloads and you find foo(x) where the type doesn't match, you again don't know whether you've found the right method until you are sure that there's no foo(y: Y) where Y does match the type.)

  --Rex

Jason Zaugg

unread,
Sep 20, 2013, 5:27:28 PM9/20/13
to Rex Kerr, Shelby, scala-debate
On Fri, Sep 20, 2013 at 11:12 PM, Rex Kerr <ich...@gmail.com> wrote:
On Fri, Sep 20, 2013 at 11:04 AM, Shelby <she...@coolpage.com> wrote:
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing

I think you're underestimating the amount of ambiguity to be had.

def foo(a: Int)(implicit b: Int): Array[Int] = Array(b, a)
implicit val x = 5
val bar = foo(3)(1)

What is the type of bar?  What is the result?  Is it 3 or Array(1,3)?

It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

Actually, I was meaning to write a lint check to flag a pretty similar case (def f / def f(implicit ...)). [1]

It was sufficiently subtle to lead a certain language designer astray for a day or two.

That case also showed that the duelling methods need not be proximal given inheritance.

I think this is a good area for a linters, rather than baking the rules into the specification for overload resolution.

-jason

Simon Ochsenreither

unread,
Sep 20, 2013, 5:54:46 PM9/20/13
to scala-...@googlegroups.com
I hope you never use Java. :-)

Shelby

unread,
Sep 20, 2013, 11:12:51 PM9/20/13
to scala-...@googlegroups.com, Shelby
On Saturday, September 21, 2013 5:12:06 AM UTC+8, Rex Kerr wrote:
On Fri, Sep 20, 2013 at 11:04 AM, Shelby <she...@coolpage.com> wrote:
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing

I think you're underestimating the amount of ambiguity to be had.

def foo(a: Int)(implicit b: Int): Array[Int] = Array(b, a)
implicit val x = 5
val bar = foo(3)(1)

What is the type of bar?  What is the result?  Is it 3 or Array(1,3)?

That is reasonable point to raise, yet I don't see any ambiguity above, because the programmer has communicated his intention unambiguously analogous to we don't imagine what the ambiguity would be in a case where we require a cast and use a cast, e.g.

trait A
trait B extends A
case class C extends B
case class D extends A

implicit def DFromC(a: C) = D

def foo(a: B) ...
def foo(a: D) ....

val bar = foo(C : B)

Would you argue the above is any way ambiguously specified by the programmer?
 
It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

I define ambiguous is there is nothing the programmer has written to give the compiler an unambiguous indication of the priority to choose. With that definition can you show me something in Scala that is ambiguous besides what I am arguing is a bug in the specification in this thread?

This is one of the taxes you have to pay to gain the expressive power of Scala.

I am not convinced. I don't like to assume that expressive power necessarily requires loss of correctness.

If you can show me that is the case, then I will acquiesce.

Making a rule that foo(x) means foo(x), not foo(x, defaultY) seems fine to me.

I strongly and emphatically disagree and if I could scream louder I would. This is a defeatist philosophy IMO (not you personally but the overall thrust to allow such logic into the language design and I would like to try to put a stop to it, if we can get consensus).

The reason is because as you say, there are many complex combinations that can occur with the various expressive power features in Scala, thus when the user writes the above, they may not even consciously realize they've made such a choice. Why would they write it, if the default can never be employed. It an entirely useful snippet of code they have written, and so they must not be aware of it, otherwise they wouldn't write it.

And more saliently, because choices between ambiguities should be explicitly specified by the programmer, so that intent is conscious.
 
  You do need to know it, and you can if you choose use it to obfuscate your code, but in any reasonably constructed and properly documented code it shouldn't be an issue at all because (1) foo(x) and foo(x, y = Y) are next to each other in the code, and (2) they're also next to each other in the Scaladoc.

Rex I hope you don't get offended if I say that if we start allowing that sort of sweeping incorrectness under the rug, we've lost. I am amazed you would use excuses about how humans shouldn't err, to justify incorrectness in the language design. Perhaps I am just not seeing how pervasive ambiguities are in the language already? Perhaps that is why you are deferring to "it isn't a big deal"?

If you're going to allow overloads at all, that is.  (If you allow overloads and you find foo(x) where the type doesn't match, you again don't know whether you've found the right method until you are sure that there's no foo(y: Y) where Y does match the type.)

Yup. So what is the problem? The compiler needs to search all the possibilities. It is already searching for really obscure matches:


I have added several comments below answers at SO/SE to argue that overloading is useful and is not evil:


What is evil IMO is expecting overloading to be what it isn't, or diminishing the importance of having one name for a common semantic. 

Shelby

unread,
Sep 20, 2013, 11:18:08 PM9/20/13
to scala-...@googlegroups.com, Shelby
IMO Google groups really needs a preview feature. And perhaps also an edit feature (with a Post Delayed button) where they don't send the message to the list for a minute or two.


On Saturday, September 21, 2013 11:12:51 AM UTC+8, Shelby wrote:
That is reasonable point to raise

s/is/is a/
 
Why would they write it, if the default can never be employed. It an entirely useful snippet of code they have written, and so they must not be aware of it, otherwise they wouldn't write it.

s/entirely useful/entirely useless/

Shelby

unread,
Sep 20, 2013, 11:57:20 PM9/20/13
to scala-...@googlegroups.com, Rex Kerr, Shelby


On Saturday, September 21, 2013 5:27:28 AM UTC+8, Jason Zaugg wrote:
On Fri, Sep 20, 2013 at 11:12 PM, Rex Kerr <ich...@gmail.com> wrote:
On Fri, Sep 20, 2013 at 11:04 AM, Shelby <she...@coolpage.com> wrote:
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing

I think you're underestimating the amount of ambiguity to be had.

def foo(a: Int)(implicit b: Int): Array[Int] = Array(b, a)
implicit val x = 5
val bar = foo(3)(1)

What is the type of bar?  What is the result?  Is it 3 or Array(1,3)?

It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

Actually, I was meaning to write a lint check to flag a pretty similar case (def f / def f(implicit ...)). [1]

I would like to echo lexspoon's comment about the low utility (and even harm) of warnings:


IMO, we should strive for a philosophy of "It is either an error or it isn't", which forces us to be more unified and conscious of how we design the language.
 
It was sufficiently subtle to lead a certain language designer astray for a day or two.

That case also showed that the duelling methods need not be proximal given inheritance.

Thanks for the example. And you are definitely not a n00b who can't read the specification.

I wish we would stop blaming (sweeping under the rug) our language design errors on the n00bs, because it is almost (if not) always wrong.
 
I think this is a good area for a linters, rather than baking the rules into the specification for overload resolution.

Emphatically disagree.
 


See my comments under Martin's answer:


[I have some comments]( http://stackoverflow.com/a/2512001/615784 ) (see my comments below the linked answer) about Scala making overloading frowned upon and a second-class citizen. If we continue to purposely weaken overloading in Scala, we are replacing typing with names, which IMO is a regressive direction.


On Saturday, September 21, 2013 5:54:46 AM UTC+8, Simon Ochsenreither wrote:
I hope you never use Java. :-)

Java got more things correct than we appear to recognize, c.f. my comments at above link (i.e. type erasure is best). Add the Java philosophy of restriction against defining new symbol operators (yet I think Java is overly restrictive, there needs to be some balance). 

Rex Kerr

unread,
Sep 20, 2013, 11:57:25 PM9/20/13
to Shelby, scala-debate
On Fri, Sep 20, 2013 at 8:12 PM, Shelby <she...@coolpage.com> wrote:
On Saturday, September 21, 2013 5:12:06 AM UTC+8, Rex Kerr wrote:

On Fri, Sep 20, 2013 at 11:04 AM, Shelby <she...@coolpage.com> wrote:
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing

I think you're underestimating the amount of ambiguity to be had.

def foo(a: Int)(implicit b: Int): Array[Int] = Array(b, a)
implicit val x = 5
val bar = foo(3)(1)

What is the type of bar?  What is the result?  Is it 3 or Array(1,3)?

That is reasonable point to raise, yet I don't see any ambiguity above, because the programmer has communicated his intention unambiguously

Really?  So, uh, which is it?

Argument for one way:
  val temp = foo(3)
  val bar = temp(1)

Argument for another way:

  (foo _)
  Int => Int => Array[Int]

Can you explain why this is so unambiguous?
 
analogous to we don't imagine what the ambiguity would be in a case where we require a cast and use a cast, e.g.

trait A
trait B extends A
case class C extends B
case class D extends A

implicit def DFromC(a: C) = D

def foo(a: B) ...
def foo(a: D) ....

val bar = foo(C : B)

I don't see the analogy.  You will have to spell out the parallels; this looks entirely different to me.  (In particular, I don't know why you bother with C: B; C should do the trick alone.)
 

It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

I define ambiguous is there is nothing the programmer has written to give the compiler an unambiguous indication of the priority to choose. With that definition can you show me something in Scala that is ambiguous besides what I am arguing is a bug in the specification in this thread?

object O {
  def f(l: Long) = l*l
  def f(d: Double) = 1.0/d
}

O.f(5)  // What do I print?
 

This is one of the taxes you have to pay to gain the expressive power of Scala.

I am not convinced. I don't like to assume that expressive power necessarily requires loss of correctness.

That implicit arguments normally vanish into thin air is exactly one of these cases.  (See my first example.)
 

If you can show me that is the case, then I will acquiesce.

Making a rule that foo(x) means foo(x), not foo(x, defaultY) seems fine to me.

I strongly and emphatically disagree and if I could scream louder I would. This is a defeatist philosophy IMO (not you personally but the overall thrust to allow such logic into the language design and I would like to try to put a stop to it, if we can get consensus).

The reason is because as you say, there are many complex combinations that can occur with the various expressive power features in Scala, thus when the user writes the above, they may not even consciously realize they've made such a choice. Why would they write it, if the default can never be employed. It an entirely useless snippet of code they have written, and so they must not be aware of it, otherwise they wouldn't write it.

Within the same class, yes, you can't use the default value.  But

class A { def foo(a: Int, b: Long = 0) = a + b }
class B extends A { def foo(a: Int): Long = foo(a, 1) }

so the question is whether it's worth a special case (and whether it should be an error or a warning or only come up with a lint-like tool).

 

And more saliently, because choices between ambiguities should be explicitly specified by the programmer, so that intent is conscious.
 
  You do need to know it, and you can if you choose use it to obfuscate your code, but in any reasonably constructed and properly documented code it shouldn't be an issue at all because (1) foo(x) and foo(x, y = Y) are next to each other in the code, and (2) they're also next to each other in the Scaladoc.

Rex I hope you don't get offended if I say that if we start allowing that sort of sweeping incorrectness under the rug, we've lost.

See the valid use case above.
 

If you're going to allow overloads at all, that is.  (If you allow overloads and you find foo(x) where the type doesn't match, you again don't know whether you've found the right method until you are sure that there's no foo(y: Y) where Y does match the type.)

Yup. So what is the problem? The compiler needs to search all the possibilities.

The problem is that the _coder_ needs to search all the possibilities.  (Or the IDE.)  Otherwise, how do you know whether you've missed the exact match?

Without implicits, it's much easier: if the type doesn't match the method, you ignore it.

  --Rex
 

Shelby

unread,
Sep 21, 2013, 12:31:31 AM9/21/13
to scala-...@googlegroups.com, Shelby
On Saturday, September 21, 2013 11:57:25 AM UTC+8, Rex Kerr wrote:
On Fri, Sep 20, 2013 at 8:12 PM, Shelby <she...@coolpage.com> wrote:
On Saturday, September 21, 2013 5:12:06 AM UTC+8, Rex Kerr wrote:

On Fri, Sep 20, 2013 at 11:04 AM, Shelby <she...@coolpage.com> wrote:
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing

I think you're underestimating the amount of ambiguity to be had.

def foo(a: Int)(implicit b: Int): Array[Int] = Array(b, a)
implicit val x = 5
val bar = foo(3)(1)

What is the type of bar?  What is the result?  Is it 3 or Array(1,3)?

That is reasonable point to raise, yet I don't see any ambiguity above, because the programmer has communicated his intention unambiguously

Really?  So, uh, which is it?

Argument for one way:
  val temp = foo(3)
  val bar = temp(1)

Argument for another way:

  (foo _)
  Int => Int => Array[Int]

Can you explain why this is so unambiguous?

I understood that point from your prior post, yet the prior example code is not assigning the curried partial function to another value, rather it is explicitly supply the 2nd argument immediately.

With your new example above, temp should contain the result of the function with the implicit argument applied.

There is no ambiguity because the choice is made at each local decision point, not across multiple expressions.
 
analogous to we don't imagine what the ambiguity would be in a case where we require a cast and use a cast, e.g.

trait A
trait B extends A
case class C extends B
case class D extends A

implicit def DFromC(a: C) = D

def foo(a: B) ...
def foo(a: D) ....

val bar = foo(C : B)

I don't see the analogy.  You will have to spell out the parallels; this looks entirely different to me.

The parallel is the order of local decisions. The most local (inner-most) decision is cast from C to B, then next one follows it, which is choosing which overload inputs a B. Thus no ambiguity. If instead you tried to allow some global conceptualization, you would imagine an ambiguity there, but that is not the way programming works (at least not any sane programming I have ever been exposed to).
 
  (In particular, I don't know why you bother with C: B; C should do the trick alone.)

Just to illustrate the concept. And there are cases in life where a C adds functionality to a B.

It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

I define ambiguous is there is nothing the programmer has written to give the compiler an unambiguous indication of the priority to choose. With that definition can you show me something in Scala that is ambiguous besides what I am arguing is a bug in the specification in this thread?

object O {
  def f(l: Long) = l*l
  def f(d: Double) = 1.0/d
}

O.f(5)  // What do I print?

Neither. Should be an error, "ambiguous overloads". Is this not an error in Scala?
 
This is one of the taxes you have to pay to gain the expressive power of Scala.

I am not convinced. I don't like to assume that expressive power necessarily requires loss of correctness.

That implicit arguments normally vanish into thin air is exactly one of these cases.  (See my first example.)

I don't see the ambiguity.
 
If you can show me that is the case, then I will acquiesce.

Making a rule that foo(x) means foo(x), not foo(x, defaultY) seems fine to me.

I strongly and emphatically disagree and if I could scream louder I would. This is a defeatist philosophy IMO (not you personally but the overall thrust to allow such logic into the language design and I would like to try to put a stop to it, if we can get consensus).

The reason is because as you say, there are many complex combinations that can occur with the various expressive power features in Scala, thus when the user writes the above, they may not even consciously realize they've made such a choice. Why would they write it, if the default can never be employed. It an entirely useless snippet of code they have written, and so they must not be aware of it, otherwise they wouldn't write it.

Within the same class, yes, you can't use the default value.  But

class A { def foo(a: Int, b: Long = 0) = a + b }
class B extends A { def foo(a: Int): Long = foo(a, 1) }

so the question is whether it's worth a special case (and whether it should be an error or a warning or only come up with a lint-like tool).

Huh? You still haven't employed the default value.

What special case? The simple rule is that ambiguous overloads should always be an error. No exceptions ever. No warnings.
 
And more saliently, because choices between ambiguities should be explicitly specified by the programmer, so that intent is conscious.
 
  You do need to know it, and you can if you choose use it to obfuscate your code, but in any reasonably constructed and properly documented code it shouldn't be an issue at all because (1) foo(x) and foo(x, y = Y) are next to each other in the code, and (2) they're also next to each other in the Scaladoc.

Rex I hope you don't get offended if I say that if we start allowing that sort of sweeping incorrectness under the rug, we've lost.

See the valid use case above.

I didn't see any valid use case ambiguities above.


If you're going to allow overloads at all, that is.  (If you allow overloads and you find foo(x) where the type doesn't match, you again don't know whether you've found the right method until you are sure that there's no foo(y: Y) where Y does match the type.)

Yup. So what is the problem? The compiler needs to search all the possibilities.

The problem is that the _coder_ needs to search all the possibilities.  (Or the IDE.)  Otherwise, how do you know whether you've missed the exact match?

Without implicits, it's much easier: if the type doesn't match the method, you ignore it.

The compiler will search for the implicits in scope. The programmer will receive an error if there is an ambiguity, and otherwise if an implicit causes an action that the programmer did not expect, blame that on the choice to use implicits, not on overloading because it can happen even without overloading.

Implicits are powerful and also silently dangerous. However, the IDE marks now every where an implicit was utilized. So I really don't see the problem.

Kudos to those who improved the IDE. Has really made a huge difference IMO.

Rex Kerr

unread,
Sep 21, 2013, 2:33:15 PM9/21/13
to Shelby, scala-debate
On Fri, Sep 20, 2013 at 9:31 PM, Shelby <she...@coolpage.com> wrote:
On Saturday, September 21, 2013 11:57:25 AM UTC+8, Rex Kerr wrote:

On Fri, Sep 20, 2013 at 8:12 PM, Shelby <she...@coolpage.com> wrote:
On Saturday, September 21, 2013 5:12:06 AM UTC+8, Rex Kerr wrote:

On Fri, Sep 20, 2013 at 11:04 AM, Shelby <she...@coolpage.com> wrote:
Specification the silently chooses an ambiguous overload is wrong at any level of programmer sophistication, for the same reason that we use static typing

I think you're underestimating the amount of ambiguity to be had.

def foo(a: Int)(implicit b: Int): Array[Int] = Array(b, a)
implicit val x = 5
val bar = foo(3)(1)

What is the type of bar?  What is the result?  Is it 3 or Array(1,3)?

That is reasonable point to raise, yet I don't see any ambiguity above, because the programmer has communicated his intention unambiguously

Really?  So, uh, which is it?

Argument for one way:
  val temp = foo(3)
  val bar = temp(1)

Argument for another way:

  (foo _)
  Int => Int => Array[Int]

Can you explain why this is so unambiguous?

I understood that point from your prior post, yet the prior example code is not assigning the curried partial function to another value, rather it is explicitly supply the 2nd argument immediately.

With your new example above, temp should contain the result of the function with the implicit argument applied.

There is no ambiguity because the choice is made at each local decision point, not across multiple expressions.

I think you're cheating, in a sense, because I gave away the function signature at the beginning.  But if you are well aware of your function signatures, then this isn't any more or less ambiguous than the one-arg vs. two-arg-with-one-implicit case.

In practice, you probably first encounter something like this:

  val x: Array[Int] = baz(7)
  val y: Array[Int] = baz(2)
  baz(3)(5)

You don't think it might be tempting to conclude that baz(3)(5) is element 5 of an array of integers?

It had _better_ be tempting to think that, because you can write baz so that's what it gives you.  You can also write baz other ways to give Array[Int] or something completely different.

 

It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

I define ambiguous is there is nothing the programmer has written to give the compiler an unambiguous indication of the priority to choose. With that definition can you show me something in Scala that is ambiguous besides what I am arguing is a bug in the specification in this thread?

object O {
  def f(l: Long) = l*l
  def f(d: Double) = 1.0/d
}

O.f(5)  // What do I print?

Neither. Should be an error, "ambiguous overloads". Is this not an error in Scala?

It's runnable code.  Why not run it instead of asking?
 
 
This is one of the taxes you have to pay to gain the expressive power of Scala.

I am not convinced. I don't like to assume that expressive power necessarily requires loss of correctness.

That implicit arguments normally vanish into thin air is exactly one of these cases.  (See my first example.)

I don't see the ambiguity.

It's ambiguous until you dig enough.  Then it isn't.  Same deal with foo(x) vs. foo(x, y) w/ default y.
 
 
If you can show me that is the case, then I will acquiesce.

Making a rule that foo(x) means foo(x), not foo(x, defaultY) seems fine to me.

I strongly and emphatically disagree and if I could scream louder I would. This is a defeatist philosophy IMO (not you personally but the overall thrust to allow such logic into the language design and I would like to try to put a stop to it, if we can get consensus).

The reason is because as you say, there are many complex combinations that can occur with the various expressive power features in Scala, thus when the user writes the above, they may not even consciously realize they've made such a choice. Why would they write it, if the default can never be employed. It an entirely useless snippet of code they have written, and so they must not be aware of it, otherwise they wouldn't write it.

Within the same class, yes, you can't use the default value.  But

class A { def foo(a: Int, b: Long = 0) = a + b }
class B extends A { def foo(a: Int): Long = foo(a, 1) }

so the question is whether it's worth a special case (and whether it should be an error or a warning or only come up with a lint-like tool).

Huh? You still haven't employed the default value.

I changed the effective default value for classes typed as B.
 
What special case? The simple rule is that ambiguous overloads should always be an error. No exceptions ever. No warnings.

Is the case above ambiguous or not?  I can't tell based on your criterion.

I agree in principle, but detecting honest ambiguity is surprisingly difficult.  I'm not sure it's a clear win when the statement of what is ambiguous is too difficult.  (And your compiler either needs to contain a general proof system or a special rule for each case.)

Anyway, it might be kind of nice if the compiler poked you if you wrote that kind of ambiguity.  But the implication that you can't trust a compiler that doesn't poke you, when there are so many other ways in which you could be confused much worse, contains rather ridiculous amounts of hyperbole.
 
  --Rex

Simon Ochsenreither

unread,
Sep 21, 2013, 3:49:55 PM9/21/13
to scala-...@googlegroups.com, Shelby

IMO Google groups really needs a preview feature. And perhaps also an edit feature (with a Post Delayed button) where they don't send the message to the list for a minute or two.

I would really appreciate that.

Shelby

unread,
Sep 22, 2013, 12:01:11 AM9/22/13
to scala-...@googlegroups.com, Shelby
IMO you are conflating syntactical ambiguity with lack of ability of the programmer to infer types. The latter is aided by the IDE, e.g. the implicits should be marked in the IDE.

In my PoV, syntactical ambiguity is very well defined and always local.

I am thinking this is the only sane (coherent) paradigm to conceptualize a compiler strategy.

If someone can convince me otherwise, I am listening. Otherwise I am going to move forward on what I want Scala to be, consensus or no consensus. So please try to convince me of what is correct or where my myopia lies if any.

I am determined to have the perfect language and compiler, because I want to write a lot of code and I don't want it to have a half-life of a few years. I want for example Eric Raymond's GIF code is still in wide use decades hence.
 
It's not hard to make constructs that can be ambiguous, especially in the presence of optional parameters, optional parameter lists, and implicit conversions.

I define ambiguous is there is nothing the programmer has written to give the compiler an unambiguous indication of the priority to choose. With that definition can you show me something in Scala that is ambiguous besides what I am arguing is a bug in the specification in this thread?

object O {
  def f(l: Long) = l*l
  def f(d: Double) = 1.0/d
}

O.f(5)  // What do I print?

Neither. Should be an error, "ambiguous overloads". Is this not an error in Scala?

It's runnable code.  Why not run it instead of asking?

Why is it not ambiguous? Some implicit conversion from long to double?

If yes, IMO that is a design error and a bug. Clearly that is an ambiguous overload and should be an error.

I'd would rather have to make a cast sometimes to be explicit than fill the language with silent ambiguities. I think the desire to make Scala more like a scripting language (where you don't specify types) was a bad tradeoff.

If I want a scripting language, there are many, e.g. Python.
 
This is one of the taxes you have to pay to gain the expressive power of Scala.

I am not convinced. I don't like to assume that expressive power necessarily requires loss of correctness.

That implicit arguments normally vanish into thin air is exactly one of these cases.  (See my first example.)

I don't see the ambiguity.

It's ambiguous until you dig enough.  Then it isn't.  Same deal with foo(x) vs. foo(x, y) w/ default y.

Example?

I am still not seeing it. It appears you have a different concept of ambiguity which is not well defined. My concept of ambiguity is very concrete and easy to specify with one paragraph.

If you can show me that is the case, then I will acquiesce.

Making a rule that foo(x) means foo(x), not foo(x, defaultY) seems fine to me.

I strongly and emphatically disagree and if I could scream louder I would. This is a defeatist philosophy IMO (not you personally but the overall thrust to allow such logic into the language design and I would like to try to put a stop to it, if we can get consensus).

The reason is because as you say, there are many complex combinations that can occur with the various expressive power features in Scala, thus when the user writes the above, they may not even consciously realize they've made such a choice. Why would they write it, if the default can never be employed. It an entirely useless snippet of code they have written, and so they must not be aware of it, otherwise they wouldn't write it.

Within the same class, yes, you can't use the default value.  But

class A { def foo(a: Int, b: Long = 0) = a + b }
class B extends A { def foo(a: Int): Long = foo(a, 1) }

so the question is whether it's worth a special case (and whether it should be an error or a warning or only come up with a lint-like tool).

Huh? You still haven't employed the default value.

I changed the effective default value for classes typed as B.

As far as I can see irrelevant to the point I originally made (about an overload making the method with the default entirely useless) because never has the method with the default value been called employing the default. Thus my point remains that the default value is entirely useless there, because it is never used.

What special case? The simple rule is that ambiguous overloads should always be an error. No exceptions ever. No warnings.

Is the case above ambiguous or not?  I can't tell based on your criterion.

Which example are you referring to?

I agree in principle, but detecting honest ambiguity is surprisingly difficult.  I'm not sure it's a clear win when the statement of what is ambiguous is too difficult.  (And your compiler either needs to contain a general proof system or a special rule for each case.)

I think it is very concrete and very simple rule in my concept of ambiguity. Does your concept of ambiguity have a plausible specification?
 
Anyway, it might be kind of nice if the compiler poked you if you wrote that kind of ambiguity.  But the implication that you can't trust a compiler that doesn't poke you, when there are so many other ways in which you could be confused much worse, contains rather ridiculous amounts of hyperbole.

If we don't define ambiguity then yes. But I have defined it very concretely. It is always local.

As for other proliferated forms of misunderstanding, the IDE is one aid. But that is irrelevant to the definition of ambiguity that the compiler can deal with deterministically.
 
 
  --Rex

Shelby

unread,
Sep 22, 2013, 12:08:45 AM9/22/13
to scala-...@googlegroups.com, Shelby
I still want to minimize writing types where it isn't necessary. I am not advocating trashing the goal of being less noisy.
Reply all
Reply to author
Forward
0 new messages