-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Adding a useless assignment statement alters program behavior. #21649
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
Comments
I don't have the phone where I can just ask it what forum topic was I reading where I linked to a scala 2 ticket about partial functions, but that ticket has a discussion about the equivalence of the function shape The spec may need to iron out details, but the assumption that adding a statement doesn't matter isn't correct. Maybe it is worth a lint. |
If your comment "Maybe it is worth a lint." means running scalafix, I just did, with no warnings. Thanks. |
And would "the assumption that adding a useless statement doesn't matter is correct" be true ? |
So different source code emits different bytecode. How is the behaviour observably different at runtime? Is there a test case (as basic as a main with asserts) that captures an unexpected difference in behaviour between the two? |
By "worth a lint", I meant that someone should add code to lint (internal lint in scalac or external in scalafix):
The old scala 2 ticket: For the |
Hi all, I would like to add a couple of examples showing why this is a bug, in my opinion. Consider the following code (all code uses scala2 syntax, since I tested it on scala 2.13, 3.3 and 3.5):
The output is:
So, calling Here is another example:
The output is:
So, in this case, As I said above, I tested code with scala 2.13, 3.3 and 3.5 and the behavior is exactly the same. In my opinion this is a bug, since |
I agree that there's something missing here (quite a lot, actually). First, I could not find any point in the spec where it is defined what kind of lambdas can implement partial functions. If I missed it, please point it out. A spec would be the first thing to look at for a decision what should be done. Worse, I did not find any treatment of single abstract method types in the Scala spec. It seems PartialFunctions are treated as a special case of this. Now if we look at the definition of val sample = 1 to 10
def isEven(n: Int) = n % 2 == 0
val eveningNews: PartialFunction[Int, String] = {
case x if isEven(x) => s"$x is even"
}
// The method collect is described as "filter + map"
// because it uses a PartialFunction to select elements
// to which the function is applied.
val evenNumbers = sample.collect(eveningNews)
val oddlyEnough: PartialFunction[Int, String] = {
case x if !isEven(x) => s"$x is odd"
}
// The method orElse allows chaining another PartialFunction
// to handle input outside the declared domain.
val numbers = sample.map(eveningNews orElse oddlyEnough)
// same as
val numbers = sample.map(n => eveningNews.applyOrElse(n, oddlyEnough))
val half: PartialFunction[Int, Int] = {
case x if isEven(x) => x / 2
} I believe that was the original intention. And, specifically an arbitrary lambda would not be allowed as the implementation of a x => x match
case pat1 => rhs1
...
case patN => rhsN (with the But with the arrival of SAM types in 2.12 we now do allow arbitrary lambdas as implementations and simply set the And, to make matters worse the original test also got diluted. It seems instead of only treating Now, what to do?
|
That assumption does not hold. Synthetic
|
I would like to give my perspective, that of a simple user of scala, not of a language expert. What seems odd to me is that I'm not sure why this choice was made in the first place, there are probably valid reasons I ignore. It's also obvious that it's not possible to simply change the specification of the language with the risk of breaking code that is valid today and I'm not familiar with the process of how language specification evolves, so I won't try to give any suggestion on what to do 🙂 P.S.: @som-snytt Thanks for pointing out that |
For reference, the example deemed "kind of a feature" on the linked scala 2 ticket (scala/bug#4940):
compares favorably to
The scala 2 ticket (from 2011) says it is a spec issue and includes the current example:
which did not compile in 2011 and did not compile with dotty in 2020. The example from that ticket deemed it "weird", perhaps because one might expect "magic" to transform the throwing expression into something like the explicit try:
similar to the expectation in this thread that "PF means it won't throw". My old comment was
which is as diagnosed above, SAM makes it natural. (The Scala 2 bug was that it took On further inspection, I see that we didn't entirely omit to think of updating the spec, but we didn't think of the expanded case of an arbitrary selector expression; I said I meant to give it some thought, but it was the holiday July 4 weekend in the States, which is no excuse: sjrd did review:
|
Compiler version
3.5.0, 3.5.1
Minimized code
This is a follow-up on an issue reported by Tomassino on the Scala users.scala-lang.org forum.
I created this small demo Github project to showcase this issue: https://github.com/jrlemieux/scala-weird
The two classes Test1 and Test2 inherit common code that is calling their virtual partial function outerPf_2.
The only difference between the two classes is the commenting of the useless statement "val something = p".
Expectation
It was expected that Test1.outerPf_2 would behave exactly as Test2.outerPf_2, but it doesn't.
The compiler generates very different code for the isDefinedAt method of the outerPf_2 partial functions.
For Test1:
For Test2:
The difference might be due to the fact that one PF is inlining code. But whether the compiler optimizes with inlining or not should not affect the behavior of the code. Adding an extra useless assignment statement should not affect the code's behavior.
The text was updated successfully, but these errors were encountered: