-
Notifications
You must be signed in to change notification settings - Fork 49
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
The great de-case-classification #694
The great de-case-classification #694
Conversation
Just for reference: as you know I'm using this pattern a lot in Laika since 1.0. Recently I added a new property to such a construct for the first time and I was surprised that mima forced me to nevertheless add 3 exclusions for the change of signature in the private |
Do you know if they were specific to a particular Scala version?
Mm, possibly moving the |
No, 3 errors for all 3 versions.
So just as package-private then?
I checked the bytecode and they are public. Which is another thing I don't understand, I would have thought they could be encoded more defensively in such a case? |
I think I've had the best results when I just mark as unqualified
🤷 that's a question for compiler engineers. Probably there is some trickyness / semantic mismatch between what non-public means in the JVM and for Scala. |
Yes, the package-private is not something encodable within the JVM. The problem is that since they are accessible from outside the class, they cannot be marked as From MiMA's perspective though, as long as the variable has always been package-private within this minor, it can be removed without causing a conflict (no user-land visibility means nobody could be hooked into it unless they hacked the package, which is their own fault, naughty user). |
Ok, I think I hit all the major |
@armanbilge do I understand correctly, that we are deliberately getting rid of all |
Yes, that's correct. Actually it may be possible to do that evolution bin-compatibility with some tricks, but it's definitely not possible to do it source-compatibly. We could bring back some/all of the |
Actually, I'm thinking about an approach that would let us keep sealed trait Duper {
def foo: String
def bar: Int
}
object Duper {
private case class Impl(foo: String, bar: Int) extends Duper
object fromFooBar {
def apply(foo: String, bar: Int): Duper = Impl(foo, bar)
def unapply(self: Duper) = Some((self.foo, self.bar))
}
} Therefore, both val duper = Duper.fromFooBar("123", 456)
duper match {
case Duper.fromFooBar(foo, bar) => println(s"extracted foo=$foo, bar=$bar")
} Now, if we want to add one more field to sealed trait Duper {
def foo: String
def bar: Int
def goo: Double
}
object Duper {
private case class Impl(foo: String, bar: Int, goo: Double) extends Duper
// The old object maintains the signatures of its methods unchanged.
object fromFooBar {
// inevitable need to provide some default value:
def apply(foo: String, bar: Int): Duper = Impl(foo, bar, 0.0)
def unapply(self: Duper) = Some((self.foo, self.bar))
}
// The new object gets its own apply/unapply
object fromFooBarGoo {
def apply(foo: String, bar: Int, goo: Double): Duper = Impl(foo, bar, goo)
def unapply(self: Duper) = Some((self.foo, self.bar, self.goo))
}
} So it seems, this way we can keep evolving the model without breaking any kind of compatibility. Wdyt? |
In this particular case I think I would advise against preserving
I applied this "anti-case-class-pattern" in Laika for the 1.0 release which is out since October last year, and I have not yet received a single user complaint about missing Btw. @satorg, since you recommended this pattern to us a while back: were you aware that mima does not actually accept signature changes to the |
Personally, I reckon we should get rid of the pattern matching, I don't see much of a concrete use for configuration pattern matching that isn't internal to the consumer. But willing to hear suggestions for use |
The pattern above is not about keeping But I agree that for large models maintaining any kind of |
@satorg your suggestion is similar to the pattern that Scalameta adopted for https://scalameta.org/docs/trees/guide.html#with-versioned-constructor-like-matchers
Agree.
I do sometimes use some kind of matching to transform the auto-generated CI steps in external plugins/builds. But for the reasons Jens' points out using |
I think I can take it as "it is working and not really that bad" :) |
Yes, it's workable. And not that bad for users. Probably kind of annoying for maintainers. Also we need a naming scheme. Scalameta uses versions which is honestly kind of arbitrary. |
That said, I totally agree that extractors for 5+ fields are not that practical. Especially if most of the positions are just placeholders.
The suggested matcher out there via accessing fields directly is definitely a better bet. |
Ok, thanks for the input everyone. I'm going to move forward with this as-is. We can consider restoring extractors and other things as the need comes up. |
I wonder if it makes sense to add |
Definitely don't see a reason to add Extending Anyway, we can add these later if they turn out to be important. |
So that we have a better chance to evolve these compatibly in the future, as needed.