Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

short-circuit operators not shown as by-name #143

Open
scabug opened this issue Oct 1, 2007 · 9 comments
Open

short-circuit operators not shown as by-name #143

scabug opened this issue Oct 1, 2007 · 9 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Oct 1, 2007

The Scaladoc for Boolean.&& and Boolean.|| does not list the arguments as by-name (=>).

@scabug
Copy link
Author

scabug commented Oct 1, 2007

Imported From: https://issues.scala-lang.org/browse/SI-143?orig=1
Reporter: @lexspoon

@scabug
Copy link
Author

scabug commented Jun 8, 2010

@dubochet said:
By-name arguments are printed correctly in Scaladoc 2.

@SethTisue
Copy link
Member

SethTisue commented Dec 20, 2023

&& doesn't show up as having a by-name argument at either https://www.scala-lang.org/api/2.13.12/scala/Boolean.html or https://www.scala-lang.org/api/3.3.1/scala/Boolean.html

This came up on Discord today

I don't doubt this has been handled correctly for by-name methods in general since some now-antique Scala version, but the original report was about && and || in particular

these methods are compiler fictions, I think, and it looks like the fiction needs adjusting

@SethTisue SethTisue reopened this Dec 20, 2023
@SethTisue SethTisue added this to the 2.13.13 milestone Dec 20, 2023
@SethTisue SethTisue assigned SethTisue and unassigned dubochet Dec 20, 2023
@som-snytt
Copy link

Spec at https://scala-lang.org/files/archive/spec/2.13/12-the-scala-standard-library.html#class-boolean

The Scaladoc has a "note" about the actual behavior.

The problem is not casual:

scala> def f(x: => Boolean) = 42
def f(x: => Boolean): Int

scala> val g = f _
val g: (=> Boolean) => Int = $Lambda/0x00007fb988483618@d13960e

scala> g(???)
val res0: Int = 42

scala> val g = true.|| _
val g: Boolean => Boolean = $Lambda/0x00007fb9884850f0@49653791

scala> g(???)
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
  ... 30 elided

Maybe Scala 3 will be more precise. But I guess I don't know how inline works yet:

scala> inline def f(inline x: => Boolean) = 42
def f(x: => Boolean): Int

scala> val g = f _
1 warning found
-- Warning: ------------------------------------------------------------------------------------------------------------
1 |val g = f _
  |        ^^^
  |        The syntax `<function> _` is no longer supported;
  |        you can simply leave out the trailing ` _`
val g: (=> Boolean) => Int = Lambda/0x00007f3fe851c000@120d6cbf

scala> g(???)
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
  ... 33 elided

@lexspoon
Copy link

lexspoon commented Dec 21, 2023

these methods are compiler fictions, I think, and it looks like the fiction needs adjusting

What an old ticket! While I can't remember my thinking from back then, I think I agree with the quoted text here--update the doc to show the fiction a little better.

Based on the link to the spec, the spec is using the => Boolean type. Thus, the Scaladoc output currently disagrees with the language spec.

The way the spec has it makes good sense to me. If it's a compiler fiction anyway, why not tell a simple story that teaches a little about Scala. The by-need parameter syntax is Scala's answer to short-circuiting. Unlike in Java, you can define your own methods that act like && and ||. How strange if, for the actual && and || methods, Scaladoc takes a different way to explain it.

By the way, those code samples look like bugs of their own that probably deserve a new ticket. You shouldn't be able to compile something so simple and still get a NotImplementedError.

@Ichoran
Copy link

Ichoran commented Dec 21, 2023

Now that we have inline, which is an honest description of what is happening, maybe the docs should say that? The by-name annotation, in a context where by-name annotations necessarily mean the creation of a 0-arg function option, doesn't seem particularly more helpful to me than a description stating that the argument is short-circuited.

In contrast, inline def &&(inline b: Boolean) = if a then true else b is exactly what's happening.

@SethTisue
Copy link
Member

why not tell a simple story that teaches a little about Scala

Yes, that's exactly the context in which it came up on Discord — someone new to the language, trying to understand it.

Now that we have inline, which is an honest description of what is happening, maybe the docs should say that?

Well, this is the Scala 2 bug tracker, and I'm looking to make the adjustment for Scala 2. It will show up for Scala 3 users as well of course, but in the long run the Scala 3 folks will be able to do something different in the long run if they like. Regardless, perhaps we could/should mention inline in the doc text.

@lexspoon
Copy link

That's really clever about the inline approach! I believe it only works for Scala 3, so I guess procedurally, there should be a separate ticket for any separate Scala 3 behavior.

Since I'm here now, I'll throw in two cents about how to document this for Scala 3. Thinking about it, how do we say which version is "exactly what is happening"? Since the compiler is allowed to inline in a case like this, and since both versions are equivalent after inlining (and other optimizations for the silly 0-arg function), it seems like we are in the territory of choosing which fiction to tell.

As one input on this tiny, bike-shedding question, note that the language spec uses the by-need parameter as of today:

The spec could be updated, but it seems significant that, before considering implementation concerns, the spec authors thought the by-name explanation was pretty good.

The other aspect on my mind is beginners. I think there's an argument for the brevity of the non-inline version. Imagine being a new user and having to understand an inline method right off the bat. It reminds me of trying to read some of the GNU libc headers on Linux--it has utterly arcane stuff that is basically unreadable for a lot of common functions you might be looking up.

Those are just a couple of factors, though. Thanks to everyone who looked at this!

@Ichoran
Copy link

Ichoran commented Dec 21, 2023

Imagine being a new user and having to understand by-name parameters right off the bat, though!

Inlining is conceptually related to concepts people have oodles of prior experience with, like cut-and-paste. By-name parameters are some weird arcane coding thing, as a third option instead of by-value and by-reference. Who even knows what is up with all of that? How do you get the thing to which the name refers if you didn't already compute it and stick it in there (by reference?) and didn't cut and paste the code (inlining?). (Oh, closures over the environment variables packed into a function object. Wait, what is all that?)

Once you get used to the idea of by-name parameters, it's natural. But I think it's one of the more arcane aspects of programming out there. (Variance is worse.)

@SethTisue SethTisue modified the milestones: 2.13.13, 2.13.14 Jan 22, 2024
@SethTisue SethTisue modified the milestones: 2.13.14, 2.13.15 Mar 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants