How to ensure that nobody accidentally extends case class without having to declare every case class as final

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
19 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

How to ensure that nobody accidentally extends case class without having to declare every case class as final

oss.mlists
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Rafał Krzewski
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

oss.mlists
Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
<a href="https://github.com/wartremover/wartremover" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;">https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: <a href="https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;">https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Roland Kuhn
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
<a href="https://github.com/wartremover/wartremover" target="_blank" rel="nofollow" onmousedown="this.href='https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA';return true;" onclick="this.href='https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA';return true;" class="">https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: <a href="https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala" target="_blank" rel="nofollow" onmousedown="this.href='https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg';return true;" onclick="this.href='https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg';return true;" class="">https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

oss.mlists
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev <a href="javascript:" target="_blank" gdf-obfuscated-mailto="5qJqU8zcAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">oss.m...@...:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
<a href="https://github.com/wartremover/wartremover" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;">https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: <a href="https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;">https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="5qJqU8zcAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

martin odersky-2
Have a look at the dotty compiler:


You'll see lots and lots of extensions of case classes. I believe that they are all valid use cases. So, yes, it makes definitely sense to extend case classes. 

Note also that the `enum' proposal provides a short-hand notion for case classes that are final.

Cheers

 - Martin





On Tue, Feb 28, 2017 at 11:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

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

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Oliver Ruebenacker

     Hello,

  Could you point to an example of a valid extension of a case class?

  I'd love to know the use cases, but don't want to look through the Dotty code base.

  Thanks!

     Best, Oliver

On Tue, Feb 28, 2017 at 5:54 AM, martin odersky <[hidden email]> wrote:
Have a look at the dotty compiler:


You'll see lots and lots of extensions of case classes. I believe that they are all valid use cases. So, yes, it makes definitely sense to extend case classes. 

Note also that the `enum' proposal provides a short-hand notion for case classes that are final.

Cheers

 - Martin





On Tue, Feb 28, 2017 at 11:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Oliver Ruebenacker
In reply to this post by oss.mlists

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

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

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

martin odersky-2
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <[hidden email]> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Oliver Ruebenacker

     Hello,

  Thanks for the example.

  I'd say this makes perfect sense if you can guarantee for two instances of TermRefWithSignature/TermRefWithFixedSym, that if prefix and name are the same, then sig/fixedSym is also the same. Otherwise it would not look sound to me.

     Best, Oliver

On Tue, Feb 28, 2017 at 11:02 AM, martin odersky <[hidden email]> wrote:
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <[hidden email]> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Jasper-M
Hi,

For TermRefWithSignature I think the point is that their signatures are different when they refer to different methods that have the same name and prefix. But its equals method is overridden so I don't think there's a problem: https://github.com/lampepfl/dotty/blob/355232690d96e458764159a66f3fed0135c059a3/compiler/src/dotty/tools/dotc/core/Types.scala#L1778

Kind regards,
Jasper 


Op dinsdag 28 februari 2017 17:36:03 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Thanks for the example.

  I'd say this makes perfect sense if you can guarantee for two instances of TermRefWithSignature/TermRefWithFixedSym, that if prefix and name are the same, then sig/fixedSym is also the same. Otherwise it would not look sound to me.

     Best, Oliver

On Tue, Feb 28, 2017 at 11:02 AM, martin odersky <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="bzSDNtXwAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">ode...@...> wrote:
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="bzSDNtXwAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">cur...@...> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="bzSDNtXwAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">oss.m...@...> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
<a href="https://github.com/wartremover/wartremover" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;">https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: <a href="https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;">https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="bzSDNtXwAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, <a href="http://www.type2diabetesgenetics.org/" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;">Diabetes Portal, <a href="http://www.broadinstitute.org/" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;">Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="bzSDNtXwAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend



--
Oliver Ruebenacker
Senior Software Engineer, <a href="http://www.type2diabetesgenetics.org/" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;">Diabetes Portal, <a href="http://www.broadinstitute.org/" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;">Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Oliver Ruebenacker

     Hello,

  Say, tr is a TermRef and trws is a TermRefWithSignature, and they have the same prefix and name. Do I see that right that then (tr == trws) is true and (trws == tr) is false?

  If you are overriding equals and hashCode anyway, why use case class? Can't you just use regular classes and write your own unapply method?

     Best, Oliver

On Tue, Feb 28, 2017 at 11:55 AM, Jasper-M <[hidden email]> wrote:
Hi,

For TermRefWithSignature I think the point is that their signatures are different when they refer to different methods that have the same name and prefix. But its equals method is overridden so I don't think there's a problem: https://github.com/lampepfl/dotty/blob/355232690d96e458764159a66f3fed0135c059a3/compiler/src/dotty/tools/dotc/core/Types.scala#L1778

Kind regards,
Jasper 


Op dinsdag 28 februari 2017 17:36:03 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Thanks for the example.

  I'd say this makes perfect sense if you can guarantee for two instances of TermRefWithSignature/TermRefWithFixedSym, that if prefix and name are the same, then sig/fixedSym is also the same. Otherwise it would not look sound to me.

     Best, Oliver

On Tue, Feb 28, 2017 at 11:02 AM, martin odersky <[hidden email]> wrote:
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <[hidden email]> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.

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



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

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



--

Martin Odersky
EPFL and Lightbend



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

oss.mlists
In reply to this post by Roland Kuhn
I'm starting to remember why I prohibited it in our code base.

1) It is hard to get anywhere with it because it is undocumented. It requires inappropriate amount of afford to collect all the knowledge from various unofficial sources but even then one can't be sure that it is correct.

2) It is undocumented why I should ever need to extend case class with class.

3) It is prohibited to extend case class with another case class. I understand case class as a construct which can be used in pattern matching. And as a quick way to define immutable serializable type with a generated equals/hashcode and having some generic manipulation ability through ProductN.

The case-to-case prohibition tells me that there is something unsound, mainly for pattern matching, or at least hard to implement because compiler can't do it mechanically. From top of my head:

* How to handle equality when adding fields because it doesn't fully hold in hierarchies and how and if it matters for pattern matching

* Impact of Product. How do I define correctly specific ProductN if I add additional field(s) when it has Product(N-x) already. Do I have to?

4) Some can expect that when they were able to pattern match on A case class using e.g. "case A(x)" pattern they will be able to automatically pattern match on companion object B using "case B(x)" pattern if B class inherits from A case class. It could be expected that B supports everything what A did out of the box, namely when B doesn't add fields. On a high level there is clash with general inheritance expectations.

Not inherited companion object is actually consistent with inheritance in general. But one has to realize that when pattern matching on a case class with this pattern it is working with companion object and not some kind of a special syntax. It was generated and doesn't have to be obvious. Beginner will use pattern matching mechanically and connection to companion object and unapply can be unknown to him.

Good documentation with explicit explanation could mitigate it.

5) I would find it the most straightforward to extend case class with another case class. Keeping "case" keyword along would carry the important information that subtype can be used in pattern matching. Contrary to loosing e.g. "trait" information which is not needed anymore.

6) Extending in another file creates chance for a runtime matching exception.

7) It is non-obvious that class can be used in pattern matching when it extends case class in another file due to no case keyword nearby.

8) Can miss on review that dev forgot to override equals/productness when adding fields due to missing case keyword. Linter could solve it.

9) Is inheriting from a case class requirement to make it work in pattern matching? Or class B extends class A would work as well assuming that everything what is required for pattern matching was manually implemented.

Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Jasper-M
In reply to this post by Oliver Ruebenacker

Op dinsdag 28 februari 2017 18:08:22 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Say, tr is a TermRef and trws is a TermRefWithSignature, and they have the same prefix and name. Do I see that right that then (tr == trws) is true and (trws == tr) is false?

I can't speak for the dotty developers, but it looks like they took care of that with custom equals methods.

 

  If you are overriding equals and hashCode anyway, why use case class? Can't you just use regular classes and write your own unapply method?

I think the compiler optimizes pattern matches on case classes in ways that are not possible with custom unapply methods.

 

     Best, Oliver

On Tue, Feb 28, 2017 at 11:55 AM, Jasper-M <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="QuNCeZjyAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">jaspe...@...> wrote:
Hi,

For TermRefWithSignature I think the point is that their signatures are different when they refer to different methods that have the same name and prefix. But its equals method is overridden so I don't think there's a problem: <a href="https://github.com/lampepfl/dotty/blob/355232690d96e458764159a66f3fed0135c059a3/compiler/src/dotty/tools/dotc/core/Types.scala#L1778" style="font-size:13px" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Flampepfl%2Fdotty%2Fblob%2F355232690d96e458764159a66f3fed0135c059a3%2Fcompiler%2Fsrc%2Fdotty%2Ftools%2Fdotc%2Fcore%2FTypes.scala%23L1778\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEaEPg3grxmiWZAYg2yPbkdVfLq0g&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Flampepfl%2Fdotty%2Fblob%2F355232690d96e458764159a66f3fed0135c059a3%2Fcompiler%2Fsrc%2Fdotty%2Ftools%2Fdotc%2Fcore%2FTypes.scala%23L1778\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNEaEPg3grxmiWZAYg2yPbkdVfLq0g&#39;;return true;">https://github.com/lampepfl/dotty/blob/355232690d96e458764159a66f3fed0135c059a3/compiler/src/dotty/tools/dotc/core/Types.scala#L1778

Kind regards,
Jasper 


Op dinsdag 28 februari 2017 17:36:03 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Thanks for the example.

  I'd say this makes perfect sense if you can guarantee for two instances of TermRefWithSignature/TermRefWithFixedSym, that if prefix and name are the same, then sig/fixedSym is also the same. Otherwise it would not look sound to me.

     Best, Oliver

On Tue, Feb 28, 2017 at 11:02 AM, martin odersky <[hidden email]> wrote:
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <[hidden email]> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
<a href="https://github.com/wartremover/wartremover" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGdsZcxYLTWawt35YaVoxhnZtKNRA&#39;;return true;">https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: <a href="https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fwartremover%2Fwartremover%2Fblob%2Flatest-release%2Fcore%2Fsrc%2Fmain%2Fscala%2Fwartremover%2Fwarts%2FFinalCaseClass.scala\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGqQCnu3BJfM4Q9QjsZAqpz9mdVkg&#39;;return true;">https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, <a href="http://www.type2diabetesgenetics.org/" rel="nofollow" target="_blank" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;">Diabetes Portal, <a href="http://www.broadinstitute.org/" rel="nofollow" target="_blank" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;">Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend



--
Oliver Ruebenacker
Senior Software Engineer, <a href="http://www.type2diabetesgenetics.org/" rel="nofollow" target="_blank" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;">Diabetes Portal, <a href="http://www.broadinstitute.org/" rel="nofollow" target="_blank" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;">Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="QuNCeZjyAgAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">scala-user+...@googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, <a href="http://www.type2diabetesgenetics.org/" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.type2diabetesgenetics.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFVE8xTGqlzANyuan2sVDo75uy-vA&#39;;return true;">Diabetes Portal, <a href="http://www.broadinstitute.org/" target="_blank" rel="nofollow" onmousedown="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;" onclick="this.href=&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fwww.broadinstitute.org%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHloBLjHUP5Yhb6LyVOZ-JE5b4Y5A&#39;;return true;">Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Oliver Ruebenacker

     Hello,

On Wed, Mar 1, 2017 at 9:42 AM, Jasper-M <[hidden email]> wrote:

Op dinsdag 28 februari 2017 18:08:22 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Say, tr is a TermRef and trws is a TermRefWithSignature, and they have the same prefix and name. Do I see that right that then (tr == trws) is true and (trws == tr) is false?

I can't speak for the dotty developers, but it looks like they took care of that with custom equals methods.

  Not sure what you think they "took care of". The code looks to me like (tr == trws) is true and (trws == tr) is false. Do you think it does something else?

  Such behavior can lead to surprises if, for example, you add both tr and trws to the same Set.

 

  If you are overriding equals and hashCode anyway, why use case class? Can't you just use regular classes and write your own unapply method?

I think the compiler optimizes pattern matches on case classes in ways that are not possible with custom unapply methods.

  I have no idea how the compiler handles this. But what else could it do other than checking the type and calling unapply?

     Best, Oliver
 

 

     Best, Oliver

On Tue, Feb 28, 2017 at 11:55 AM, Jasper-M <[hidden email]> wrote:
Hi,

For TermRefWithSignature I think the point is that their signatures are different when they refer to different methods that have the same name and prefix. But its equals method is overridden so I don't think there's a problem: https://github.com/lampepfl/dotty/blob/355232690d96e458764159a66f3fed0135c059a3/compiler/src/dotty/tools/dotc/core/Types.scala#L1778

Kind regards,
Jasper 


Op dinsdag 28 februari 2017 17:36:03 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Thanks for the example.

  I'd say this makes perfect sense if you can guarantee for two instances of TermRefWithSignature/TermRefWithFixedSym, that if prefix and name are the same, then sig/fixedSym is also the same. Otherwise it would not look sound to me.

     Best, Oliver

On Tue, Feb 28, 2017 at 11:02 AM, martin odersky <[hidden email]> wrote:
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <[hidden email]> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

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



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Alexandru Nedelcu-4
In reply to this post by Oliver Ruebenacker

In this particular case, MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list) I think it’s a clear case of inheritance gone wrong, because MyIntList has the invariant that sum == list.sum, whereas MyIntListWithPrecalculatedSum doesn’t, which means the Liskov Substitution Principle doesn’t hold.

One reason that OOP inheritance is hard to reason about is because the method signatures in an inheritance hierarchy don’t tell the whole story and it’s really easy to introduce a B <: A type that can’t really substitute an A.


Alexandru Nedelcu
alexn.org

On Tue, Feb 28, 2017, at 17:49, Oliver Ruebenacker wrote:


     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,


Roland


28 feb. 2017 kl. 11:05 skrev [hidden email]:


Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

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


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Jasper-M
In reply to this post by Oliver Ruebenacker
I didn't analyse it in detail, but NamedType has an equals method with special cases and TermRef extends NamedType. 

Looking at the bytecode it looks like scalac generates calls to the accessors of the case class instead of a call to unapply.

Op 1 mrt. 2017 17:27 schreef "Oliver Ruebenacker" <[hidden email]>:

     Hello,

On Wed, Mar 1, 2017 at 9:42 AM, Jasper-M <[hidden email]> wrote:

Op dinsdag 28 februari 2017 18:08:22 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Say, tr is a TermRef and trws is a TermRefWithSignature, and they have the same prefix and name. Do I see that right that then (tr == trws) is true and (trws == tr) is false?

I can't speak for the dotty developers, but it looks like they took care of that with custom equals methods.

  Not sure what you think they "took care of". The code looks to me like (tr == trws) is true and (trws == tr) is false. Do you think it does something else?

  Such behavior can lead to surprises if, for example, you add both tr and trws to the same Set.

 

  If you are overriding equals and hashCode anyway, why use case class? Can't you just use regular classes and write your own unapply method?

I think the compiler optimizes pattern matches on case classes in ways that are not possible with custom unapply methods.

  I have no idea how the compiler handles this. But what else could it do other than checking the type and calling unapply?

     Best, Oliver
 

 

     Best, Oliver

On Tue, Feb 28, 2017 at 11:55 AM, Jasper-M <[hidden email]> wrote:
Hi,

For TermRefWithSignature I think the point is that their signatures are different when they refer to different methods that have the same name and prefix. But its equals method is overridden so I don't think there's a problem: https://github.com/lampepfl/dotty/blob/355232690d96e458764159a66f3fed0135c059a3/compiler/src/dotty/tools/dotc/core/Types.scala#L1778

Kind regards,
Jasper 


Op dinsdag 28 februari 2017 17:36:03 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Thanks for the example.

  I'd say this makes perfect sense if you can guarantee for two instances of TermRefWithSignature/TermRefWithFixedSym, that if prefix and name are the same, then sig/fixedSym is also the same. Otherwise it would not look sound to me.

     Best, Oliver

On Tue, Feb 28, 2017 at 11:02 AM, martin odersky <[hidden email]> wrote:
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <[hidden email]> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].

For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

Oliver Ruebenacker
Oh, I see.

On Wed, Mar 1, 2017 at 11:39 AM, Jasper Moeys <[hidden email]> wrote:
I didn't analyse it in detail, but NamedType has an equals method with special cases and TermRef extends NamedType. 

Looking at the bytecode it looks like scalac generates calls to the accessors of the case class instead of a call to unapply.

Op 1 mrt. 2017 17:27 schreef "Oliver Ruebenacker" <[hidden email]>:


     Hello,

On Wed, Mar 1, 2017 at 9:42 AM, Jasper-M <[hidden email]> wrote:

Op dinsdag 28 februari 2017 18:08:22 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Say, tr is a TermRef and trws is a TermRefWithSignature, and they have the same prefix and name. Do I see that right that then (tr == trws) is true and (trws == tr) is false?

I can't speak for the dotty developers, but it looks like they took care of that with custom equals methods.

  Not sure what you think they "took care of". The code looks to me like (tr == trws) is true and (trws == tr) is false. Do you think it does something else?

  Such behavior can lead to surprises if, for example, you add both tr and trws to the same Set.

 

  If you are overriding equals and hashCode anyway, why use case class? Can't you just use regular classes and write your own unapply method?

I think the compiler optimizes pattern matches on case classes in ways that are not possible with custom unapply methods.

  I have no idea how the compiler handles this. But what else could it do other than checking the type and calling unapply?

     Best, Oliver
 

 

     Best, Oliver

On Tue, Feb 28, 2017 at 11:55 AM, Jasper-M <[hidden email]> wrote:
Hi,

For TermRefWithSignature I think the point is that their signatures are different when they refer to different methods that have the same name and prefix. But its equals method is overridden so I don't think there's a problem: https://github.com/lampepfl/dotty/blob/355232690d96e458764159a66f3fed0135c059a3/compiler/src/dotty/tools/dotc/core/Types.scala#L1778

Kind regards,
Jasper 


Op dinsdag 28 februari 2017 17:36:03 UTC+1 schreef Oliver Ruebenacker:

     Hello,

  Thanks for the example.

  I'd say this makes perfect sense if you can guarantee for two instances of TermRefWithSignature/TermRefWithFixedSym, that if prefix and name are the same, then sig/fixedSym is also the same. Otherwise it would not look sound to me.

     Best, Oliver

On Tue, Feb 28, 2017 at 11:02 AM, martin odersky <[hidden email]> wrote:
There are several use cases. Most commonly, we have subclasses that add specific state or override specific implementations but that do not change the nature of pattern matching. For instance

    // references to <prefix>.name
    case class TypeRef(override val prefix: Type, name: TypeName)
    
    // references to overloaded methods that in additional need a signature for disambiguation
    final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name)

    // references whose symbol is fixed
    class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym

It would make no sense to have three case classes, because we usually don't care which kind of TermRef it is when we pattern match. But at the same time, we want to cleanly distinguish the implementations. And, of course, these things are performance critical so defining separate extractors is not possible.

For more context, have a look at the dotty code base. I promise it will be instructive!

 - Martin


On Tue, Feb 28, 2017 at 4:49 PM, Oliver Ruebenacker <[hidden email]> wrote:

     Hello,

  Can't remember a use case for extending case classes in my projects, but I could imagine something like this:

  case class MyIntList(list: Seq[Int]) {
    def sum: Int = list.sum
  }

  class MyIntListWithPrecalculatedSum(list: Seq[Int], override val sum: Int) extends MyIntList(list)

     Best, Oliver

On Tue, Feb 28, 2017 at 5:47 AM, <[hidden email]> wrote:
Correct me if I'm wrong but I believe that case class shouldn't be extended, never. And the reason why it is not added in its default properties is for backward compatibility reasons. If final should be there always and it is an inherent property of a case class than why to explicitly write it?

If I look around it seems that not many use final with case classes. It seems it is an auxiliary knowledge that case classes are treated as final even they are not declared final.

I can enforce final in my code. I dislike having to write it but it is fine. But if we use 3rd party lib which has public non-final case classes than any developer can get an idea to extend it. And it seems there is no linter to catch it, I have to look for it during code review.

Assuming they should be never extended it seems better to me to have linter rule prohibiting extending and not write finale just like most do (I believe).


Petr



On Tuesday, February 28, 2017 at 11:28:55 AM UTC+1, rkuhn wrote:
May I ask what is wrong with always writing final case class? It perfectly conveys the full intent, and it expresses the desired properties not only to some external linter but also to the JVM. It is also locally and immediately visible to any reviewer, whereas the existence or configuration of the linter is not.

Regards,

Roland

28 feb. 2017 kl. 11:05 skrev [hidden email]:

Hi Rafal,
thank you. Yes, to my knowledge Scala linters either require final or are unhappy that final is redundant. Neither option is what I want.

Petr

On Wednesday, February 8, 2017 at 4:42:01 PM UTC+1, Rafał Krzewski wrote:
https://github.com/wartremover/wartremover has can enforce that each case class in your code is declared final: https://github.com/wartremover/wartremover/blob/latest-release/core/src/main/scala/wartremover/warts/FinalCaseClass.scala

Which satisfies the first part of your request but not the second :)

Cheers,
Rafał

W dniu środa, 8 lutego 2017 16:18:14 UTC+1 użytkownik [hidden email] napisał:
I just want that compilation fails hard whenever it detects that case class is extended. What are my options? I want to forbid that class extends case class for 2.11.8. Is it still possible in 2.12?

Is there a compiler flag?
Compiler plugin?
Static analysis plugin for maven/sbt?
Macro?

Thanks,
Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--

Martin Odersky
EPFL and Lightbend



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]m.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].

For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute





--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to ensure that nobody accidentally extends case class without having to declare every case class as final

oss.mlists
In reply to this post by oss.mlists
Adding to point 4) Implicit search is looking into companion objects of supertypes. Why pattern matching does not?

Another question is regarding performance sensitive use cases. Wouldn't be plain old (and ugly) Visitor pattern even faster? The performance gain maybe doesn't overweight added ugliness though.

Petr

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Loading...