- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Re: Do you use case class inheritance?
Fri, 2009-04-03, 15:38
>>>>> "David" == David MacIver writes:
David> There has been some discussion recently about deprecating case
David> class inheritance (i.e. the ability to have case class Foo(...)
David> and case class Bar(...) extends Foo(...)).
I'd like to offer the list this quote from Martin O, from the
scala-internals list:
martin> (I also noted a rather unfortunate misunderstanding where
martin> newbies start with an abstract case class extended by other
martin> case classes; they did not intend to match on the abstract
martin> class; they were just unsure where to put the case, so they put
martin> it everywhere).
because I only stopped making this newbie mistake quite recently, so
maybe others are still making it too and will want to know about it :-)
Thu, 2009-04-23, 19:27
#2
Re: Do you use case class inheritance?
>>>>> "David" == David MacIver writes:
David> 2009/4/3 James Iry :
>> You only need to seal once. "sealed" means "can't extend hierarchy
>> outside of this compilation unit." The question is, can StringValue
>> be an ordinary abstract class or even a trait?
David> I can definitely see the desire to be able to do "case
David> StringValue(someString) => " here. It does seem like a valid use
David> case.
For the record, without case class inheritance, instead of
case class StringValue(value:String) extends CSValue
you write:
trait StringValue extends CSValue { def value : String }
object StringValue { def unapply(s:StringValue) = Some(s.value) }
which is not as nice, certainly, but given that this is the only
real objection that has been raised to deprecating or eliminating
case class inheritance, it seems not so bad.
Thu, 2009-04-23, 19:37
#3
Re: Do you use case class inheritance?
>>>>> "Justin" == Justin du coeur writes:
Justin> Okay, here's a question from a newbie, trying to understand the
Justin> implications. Having read the comment that Seth quoted, and
Justin> digested it a little, do I correctly understand that standard
Justin> best practice is to have an abstract conventional super-class,
Justin> with case classes used only as the leaves of the inheritance
Justin> tree? (If so, Martin's comment is right: that's not obvious to
Justin> newbies, and probably ought to be called out a bit more loudly
Justin> in the book.) And what you're proposing is to make that more
Justin> mandatory -- that case classes cannot be inner nodes of the
Justin> tree, only leaves?
Justin> If so, I can't say that I have any specific immediate
Justin> objections to it: my expected uses for case classes do all seem
Justin> to be at the leaves. But I do find it a little unintuitive,
Justin> coming from the viewpoint of more ordinary OO languages. It
Justin> roughly says that case classes are automatically sealed, and I
Justin> don't generally think of sealed as being quite so common.
Justin> worry a little about the implications for being able to add
Justin> little tweaks to things down the line, but it's a pretty
Justin> hypothetical concern: if practice has shown that people really
Justin> aren't doing this, then it probably indicates that that's okay.
I think someone probably already said this, but just in case:
This change wouldn't mean case classes are sealed. You could still
derive an ordinary class, trait, or object from a case class. You just
couldn't derive another case class.
Thu, 2009-04-23, 19:57
#4
Re: Do you use case class inheritance?
If case class inheritance goes away, I'm going to have to duplicate that noisy, non-semantic logic
throughout all the places in my AST where I was previously using case class inheritance. While "it
seems not so bad" in one isolated case in one isolated place, having to use that idiom repetitively
is going to get very tiring very quickly.
Maybe I'm just going the wrong way? What I'm trying to do is mimic OCaml's variant types to
represent my AST, so that walking the tree is a bunch of recursive pattern matching, and my
implementation is checked for completeness by the compiler.
In OCaml, it'd be something like this:
# type intvalue = Int of int;;
# type stringvalue = Rich of string | Literal of string;;
# type csvalue = StringValue of stringvalue | IntValue of intvalue;;
~~ Robert.
Seth Tisue wrote:
>>>>>> "David" == David MacIver writes:
>
> David> 2009/4/3 James Iry :
> >> You only need to seal once. "sealed" means "can't extend hierarchy
> >> outside of this compilation unit." The question is, can StringValue
> >> be an ordinary abstract class or even a trait?
>
> David> I can definitely see the desire to be able to do "case
> David> StringValue(someString) => " here. It does seem like a valid use
> David> case.
>
> For the record, without case class inheritance, instead of
>
> case class StringValue(value:String) extends CSValue
>
> you write:
>
> trait StringValue extends CSValue { def value : String }
> object StringValue { def unapply(s:StringValue) = Some(s.value) }
>
> which is not as nice, certainly, but given that this is the only
> real objection that has been raised to deprecating or eliminating
> case class inheritance, it seems not so bad.
>
Thu, 2009-04-23, 23:27
#5
Re: Do you use case class inheritance?
I don't promise to have the full answer, but perhaps model with containment rather than subclassing?
sealed abstract class stringvalue
final case class Rich(x : String) extends stringvalue
final case class Literal(x : String) extends stringvalue
sealed abstract class CSValue
final case class IntValue(x : Int) extends CSValue
final case class StringValue(x : stringvalue) extends CSValue
Hmmm, that does mean you are forced to pattern match recursively - there's not flat option as there is with case class inheritance
x : CSValue = ...
x match {
case IntValue(i) => ...
case StringValue(s) =>
s match {
case Rich(r) => ...
case Literal(l) =>...
}
}
Like I say, I don't have the full answer.
On Thu, Apr 23, 2009 at 11:54 AM, Robert Fischer <robert.fischer@smokejumperit.com> wrote:
sealed abstract class stringvalue
final case class Rich(x : String) extends stringvalue
final case class Literal(x : String) extends stringvalue
sealed abstract class CSValue
final case class IntValue(x : Int) extends CSValue
final case class StringValue(x : stringvalue) extends CSValue
Hmmm, that does mean you are forced to pattern match recursively - there's not flat option as there is with case class inheritance
x : CSValue = ...
x match {
case IntValue(i) => ...
case StringValue(s) =>
s match {
case Rich(r) => ...
case Literal(l) =>...
}
}
Like I say, I don't have the full answer.
On Thu, Apr 23, 2009 at 11:54 AM, Robert Fischer <robert.fischer@smokejumperit.com> wrote:
If case class inheritance goes away, I'm going to have to duplicate that noisy, non-semantic logic throughout all the places in my AST where I was previously using case class inheritance. While "it seems not so bad" in one isolated case in one isolated place, having to use that idiom repetitively is going to get very tiring very quickly.
Maybe I'm just going the wrong way? What I'm trying to do is mimic OCaml's variant types to represent my AST, so that walking the tree is a bunch of recursive pattern matching, and my implementation is checked for completeness by the compiler.
In OCaml, it'd be something like this:
# type intvalue = Int of int;;
# type stringvalue = Rich of string | Literal of string;;
# type csvalue = StringValue of stringvalue | IntValue of intvalue;;
~~ Robert.
Seth Tisue wrote:
"David" == David MacIver <david.maciver@gmail.com> writes:
David> 2009/4/3 James Iry <jamesiry@gmail.com>:
~~ Robert Fischer.
Grails Training http://GroovyMag.com/training
Smokejumper Consulting http://SmokejumperIT.com
Enfranchised Mind Blog http://EnfranchisedMind.com/blog
Check out my book, "Grails Persistence with GORM and GSQL"!
http://www.smokejumperit.com/redirect.html
Thu, 2009-04-23, 23:37
#6
Re: Do you use case class inheritance?
The matching recursively isn't really an issue -- I'm basically recursing anyway. The only
annoyance now is that I've got this wrapper type that adds no value and does nothing except to hold
an instance of my case class. But that's a lot more reasonable than that trait/unapply idiom, whose
syntax I've already forgotten.
~~ Robert.
James Iry wrote:
> I don't promise to have the full answer, but perhaps model with
> containment rather than subclassing?
>
> sealed abstract class stringvalue
> final case class Rich(x : String) extends stringvalue
> final case class Literal(x : String) extends stringvalue
>
> sealed abstract class CSValue
> final case class IntValue(x : Int) extends CSValue
> final case class StringValue(x : stringvalue) extends CSValue
>
> Hmmm, that does mean you are forced to pattern match recursively -
> there's not flat option as there is with case class inheritance
>
> x : CSValue = ...
>
> x match {
> case IntValue(i) => ...
> case StringValue(s) =>
> s match {
> case Rich(r) => ...
> case Literal(l) =>...
> }
> }
>
> Like I say, I don't have the full answer.
>
> On Thu, Apr 23, 2009 at 11:54 AM, Robert Fischer
> > wrote:
>
> If case class inheritance goes away, I'm going to have to duplicate
> that noisy, non-semantic logic throughout all the places in my AST
> where I was previously using case class inheritance. While "it
> seems not so bad" in one isolated case in one isolated place, having
> to use that idiom repetitively is going to get very tiring very quickly.
>
> Maybe I'm just going the wrong way? What I'm trying to do is mimic
> OCaml's variant types to represent my AST, so that walking the tree
> is a bunch of recursive pattern matching, and my implementation is
> checked for completeness by the compiler.
>
> In OCaml, it'd be something like this:
> # type intvalue = Int of int;;
> # type stringvalue = Rich of string | Literal of string;;
> # type csvalue = StringValue of stringvalue | IntValue of intvalue;;
>
> ~~ Robert.
>
>
> Seth Tisue wrote:
>
> "David" == David MacIver
> > writes:
>
>
> David> 2009/4/3 James Iry >:
>
>
> ~~ Robert Fischer.
> Grails Training http://GroovyMag.com/training
> Smokejumper Consulting http://SmokejumperIT.com
> Enfranchised Mind Blog http://EnfranchisedMind.com/blog
>
> Check out my book, "Grails Persistence with GORM and GSQL"!
> http://www.smokejumperit.com/redirect.html
>
>
Fri, 2009-04-24, 00:07
#7
Re: Do you use case class inheritance?
I just realized you can flatten, it's just noisy and probably gets too dense after awhile
x : CSValue = ...
x match {
case IntValue(i) => ...
case StringValue(Rich(r)) => ...
case StringValue(Literal(l)) => ...
}
On Thu, Apr 23, 2009 at 3:28 PM, Robert Fischer <robert.fischer@smokejumperit.com> wrote:
x : CSValue = ...
x match {
case IntValue(i) => ...
case StringValue(Rich(r)) => ...
case StringValue(Literal(l)) => ...
}
On Thu, Apr 23, 2009 at 3:28 PM, Robert Fischer <robert.fischer@smokejumperit.com> wrote:
The matching recursively isn't really an issue -- I'm basically recursing anyway. The only annoyance now is that I've got this wrapper type that adds no value and does nothing except to hold an instance of my case class. But that's a lot more reasonable than that trait/unapply idiom, whose syntax I've already forgotten.
~~ Robert.
James Iry wrote:
I don't promise to have the full answer, but perhaps model with containment rather than subclassing?
sealed abstract class stringvalue
final case class Rich(x : String) extends stringvalue
final case class Literal(x : String) extends stringvalue
sealed abstract class CSValue
final case class IntValue(x : Int) extends CSValue
final case class StringValue(x : stringvalue) extends CSValue
Hmmm, that does mean you are forced to pattern match recursively - there's not flat option as there is with case class inheritance
Fri, 2009-04-24, 00:17
#8
Re: Do you use case class inheritance?
To throw a spanner in, I generally (though not always) prefer abstract
data types that do not expose construction and so case class inheritance
is ruled out. I haven't been following the thread but consider if Option
did not expose None/Some users could get by with map and getOrElse
without ever having the need to pattern match.
sealed trait OptionWrapper[A] {
val option: Option[A]
def mapGetOrElse[X](some: A => X, none: => X): X = option match {
case None => none
case Some(a) => some(a)
}
// or
def fold[X](some: A => X, none: => X): X = option map some getOrElse
none
}
Robert Fischer wrote:
> The matching recursively isn't really an issue -- I'm basically
> recursing anyway. The only annoyance now is that I've got this
> wrapper type that adds no value and does nothing except to hold an
> instance of my case class. But that's a lot more reasonable than that
> trait/unapply idiom, whose syntax I've already forgotten.
>
> ~~ Robert.
>
> James Iry wrote:
>> I don't promise to have the full answer, but perhaps model with
>> containment rather than subclassing?
>>
>> sealed abstract class stringvalue
>> final case class Rich(x : String) extends stringvalue
>> final case class Literal(x : String) extends stringvalue
>>
>> sealed abstract class CSValue
>> final case class IntValue(x : Int) extends CSValue
>> final case class StringValue(x : stringvalue) extends CSValue
>>
>> Hmmm, that does mean you are forced to pattern match recursively -
>> there's not flat option as there is with case class inheritance
>>
>> x : CSValue = ...
>>
>> x match {
>> case IntValue(i) => ...
>> case StringValue(s) =>
>> s match {
>> case Rich(r) => ...
>> case Literal(l) =>...
>> }
>> }
>>
>> Like I say, I don't have the full answer.
>>
>> On Thu, Apr 23, 2009 at 11:54 AM, Robert Fischer
>> > > wrote:
>>
>> If case class inheritance goes away, I'm going to have to duplicate
>> that noisy, non-semantic logic throughout all the places in my AST
>> where I was previously using case class inheritance. While "it
>> seems not so bad" in one isolated case in one isolated place, having
>> to use that idiom repetitively is going to get very tiring very
>> quickly.
>>
>> Maybe I'm just going the wrong way? What I'm trying to do is mimic
>> OCaml's variant types to represent my AST, so that walking the tree
>> is a bunch of recursive pattern matching, and my implementation is
>> checked for completeness by the compiler.
>>
>> In OCaml, it'd be something like this:
>> # type intvalue = Int of int;;
>> # type stringvalue = Rich of string | Literal of string;;
>> # type csvalue = StringValue of stringvalue | IntValue of intvalue;;
>>
>> ~~ Robert.
>>
>>
>> Seth Tisue wrote:
>>
>> "David" == David MacIver
>> > > writes:
>>
>>
>> David> 2009/4/3 James Iry > >:
>>
>>
>> ~~ Robert Fischer.
>> Grails Training http://GroovyMag.com/training
>> Smokejumper Consulting http://SmokejumperIT.com
>> Enfranchised Mind Blog http://EnfranchisedMind.com/blog
>>
>> Check out my book, "Grails Persistence with GORM and GSQL"!
>> http://www.smokejumperit.com/redirect.html
>>
>>
>
Fri, 2009-04-24, 11:37
#9
Re: Do you use case class inheritance?
2009/4/23 Robert Fischer :
> If case class inheritance goes away, I'm going to have to duplicate that
> noisy, non-semantic logic throughout all the places in my AST where I was
> previously using case class inheritance. While "it seems not so bad" in one
> isolated case in one isolated place, having to use that idiom repetitively
> is going to get very tiring very quickly.
>
> Maybe I'm just going the wrong way? What I'm trying to do is mimic OCaml's
> variant types to represent my AST, so that walking the tree is a bunch of
> recursive pattern matching, and my implementation is checked for
> completeness by the compiler.
>
> In OCaml, it'd be something like this:
> # type intvalue = Int of int;;
> # type stringvalue = Rich of string | Literal of string;;
> # type csvalue = StringValue of stringvalue | IntValue of intvalue;;
So, this doesn't seem to need case class inheritance to emulate,
unless I'm missing something. You can introduce abstract classes (or
traits) into the tree without a problem.
The only thing you lose in having the following:
sealed abstract class CSValue extends Positional
sealed case class CSTuple(elements:List[Expression]) extends CSValue
sealed class StringValue(value:String) extends CSValue // not a case class
sealed case class LiteralStringValue(myValue:String) extends
StringValue(myValue)
sealed case class RichStringValue(pattern:String) extends StringValue(myValue)
Is that you have to match on StringValue as
case (x : StringValue) => doStuffWith(x.value);
instead of
case StringValue(value) => doStuffWith(value)
This is certainly a little unfortunate (particularly given the
increased difficulty of nesting patterns), but seems to offer
equivalent functionality to the OCaml version (if what little I know
of OCaml pattern matching is accurate).
Fri, 2009-04-24, 11:47
#10
Re: Do you use case class inheritance?
On Fri, Apr 24, 2009 at 12:25 PM, David MacIver wrote:
> 2009/4/23 Robert Fischer :
>> If case class inheritance goes away, I'm going to have to duplicate that
>> noisy, non-semantic logic throughout all the places in my AST where I was
>> previously using case class inheritance. While "it seems not so bad" in one
>> isolated case in one isolated place, having to use that idiom repetitively
>> is going to get very tiring very quickly.
>>
>> Maybe I'm just going the wrong way? What I'm trying to do is mimic OCaml's
>> variant types to represent my AST, so that walking the tree is a bunch of
>> recursive pattern matching, and my implementation is checked for
>> completeness by the compiler.
>>
>> In OCaml, it'd be something like this:
>> # type intvalue = Int of int;;
>> # type stringvalue = Rich of string | Literal of string;;
>> # type csvalue = StringValue of stringvalue | IntValue of intvalue;;
>
> So, this doesn't seem to need case class inheritance to emulate,
> unless I'm missing something. You can introduce abstract classes (or
> traits) into the tree without a problem.
>
> The only thing you lose in having the following:
>
> sealed abstract class CSValue extends Positional
> sealed case class CSTuple(elements:List[Expression]) extends CSValue
> sealed class StringValue(value:String) extends CSValue // not a case class
> sealed case class LiteralStringValue(myValue:String) extends
> StringValue(myValue)
> sealed case class RichStringValue(pattern:String) extends StringValue(myValue)
>
> Is that you have to match on StringValue as
>
> case (x : StringValue) => doStuffWith(x.value);
>
> instead of
>
> case StringValue(value) => doStuffWith(value)
>
> This is certainly a little unfortunate (particularly given the
> increased difficulty of nesting patterns), but seems to offer
> equivalent functionality to the OCaml version (if what little I know
> of OCaml pattern matching is accurate).
>
Or one could define an extractor for StringValue to do it this way. I.e:
object StringValue {
def unapply(x: StringValue) = Some(x.value)
}
Given that currently matches against inheriting case classes are done with
extractors anyway, that would not be a large change. It does make
programming this sort of nested hierarchies more difficult (need to
know about extractors). On the other hand, we are still within Alan
Kay's postulate to make simple things easy and difficult things
possible.
Cheers
Fri, 2009-04-24, 12:07
#11
Re: Do you use case class inheritance?
Perhaps the reason we all at some point go wild with case classes is that they have useful properties that take boilerplate to add to other classes. Let's suppose I want case-class-like initialisation, so that I get Foo(3) instead of new Foo(3), but I don't want anything else from case classes. I can write a companion object with the apply method in, or I can just suck in all of case classes' functionality and write the single word 'case'.
I appreciate the technical problems in this might make it a useless suggestion, but something like: class Foo(x: Int) with EasyConstruction, might make people less tempted to use case classes in places that currently cause problems, such as case class X extends CaseClassY.
2009/4/24 martin odersky <martin.odersky@epfl.ch>
I appreciate the technical problems in this might make it a useless suggestion, but something like: class Foo(x: Int) with EasyConstruction, might make people less tempted to use case classes in places that currently cause problems, such as case class X extends CaseClassY.
2009/4/24 martin odersky <martin.odersky@epfl.ch>
On Fri, Apr 24, 2009 at 12:25 PM, David MacIver <david.maciver@gmail.com> wrote:
> 2009/4/23 Robert Fischer <robert.fischer@smokejumperit.com>:
>> If case class inheritance goes away, I'm going to have to duplicate that
>> noisy, non-semantic logic throughout all the places in my AST where I was
>> previously using case class inheritance. While "it seems not so bad" in one
>> isolated case in one isolated place, having to use that idiom repetitively
>> is going to get very tiring very quickly.
>>
>> Maybe I'm just going the wrong way? What I'm trying to do is mimic OCaml's
>> variant types to represent my AST, so that walking the tree is a bunch of
>> recursive pattern matching, and my implementation is checked for
>> completeness by the compiler.
>>
>> In OCaml, it'd be something like this:
>> # type intvalue = Int of int;;
>> # type stringvalue = Rich of string | Literal of string;;
>> # type csvalue = StringValue of stringvalue | IntValue of intvalue;;
>
> So, this doesn't seem to need case class inheritance to emulate,
> unless I'm missing something. You can introduce abstract classes (or
> traits) into the tree without a problem.
>
> The only thing you lose in having the following:
>
> sealed abstract class CSValue extends Positional
> sealed case class CSTuple(elements:List[Expression]) extends CSValue
> sealed class StringValue(value:String) extends CSValue // not a case class
> sealed case class LiteralStringValue(myValue:String) extends
> StringValue(myValue)
> sealed case class RichStringValue(pattern:String) extends StringValue(myValue)
>
> Is that you have to match on StringValue as
>
> case (x : StringValue) => doStuffWith(x.value);
>
> instead of
>
> case StringValue(value) => doStuffWith(value)
>
> This is certainly a little unfortunate (particularly given the
> increased difficulty of nesting patterns), but seems to offer
> equivalent functionality to the OCaml version (if what little I know
> of OCaml pattern matching is accurate).
>
Or one could define an extractor for StringValue to do it this way. I.e:
object StringValue {
def unapply(x: StringValue) = Some(x.value)
}
Given that currently matches against inheriting case classes are done with
extractors anyway, that would not be a large change. It does make
programming this sort of nested hierarchies more difficult (need to
know about extractors). On the other hand, we are still within Alan
Kay's postulate to make simple things easy and difficult things
possible.
Cheers
Fri, 2009-04-24, 12:47
#12
Re: Do you use case class inheritance?
On Fri, 24 Apr 2009 11:55:54 +0100, Ricky Clarkson wrote:
> Perhaps the reason we all at some point go wild with case classes is that
> they have useful properties that take boilerplate to add to other classes.
> Let's suppose I want case-class-like initialisation, so that I get Foo(3)
> instead of new Foo(3), but I don't want anything else from case classes. I
> can write a companion object with the apply method in, or I can just suck in
> all of case classes' functionality and write the single word 'case'.
>
> I appreciate the technical problems in this might make it a useless
> suggestion, but something like: class Foo(x: Int) with EasyConstruction,
> might make people less tempted to use case classes in places that currently
> cause problems, such as case class X extends CaseClassY.
Actually, it looks more like annotations than marker traits.
Something like this, if it could be made to work?
(The name "deriving" is somewhat Haskell inspired and probably not the
best one.)
import scala.annotations.{deriving,Apply,Unapply,Equality,ToString}
@deriving(Apply, Unapply, Equality, ToString)
class Foo(val x: Int)
Fri, 2009-04-24, 14:57
#13
Re: Do you use case class inheritance?
Spewing a whole series of unapply definitions is really unpalatable -- I'm inheriting all over my
AST structure, so I'm going to have to use that completely non-semantic boilerplate idiom a dozen
times or so. I'm not a huge fan.
James Iry's composition approach seems to be a lot nicer:
sealed abstract class stringvalue
sealed case class Rich(x : String) extends stringvalue
sealed case class Literal(x : String) extends stringvalue
sealed abstract class CSValue
sealed case class IntValue(x : Int) extends CSValue
sealed case class StringValue(x : stringvalue) extends CSValue
I'm still having to introduce a noise type in there to make the type system work, but it gives me
basically the same functionality (modulo some additional noise in a flattened match) without having
to remember/read through the syntax for unapply.
Is there an issue with that approach I'm not seeing?
~~ Robert.
martin odersky wrote:
> On Fri, Apr 24, 2009 at 12:25 PM, David MacIver wrote:
>> 2009/4/23 Robert Fischer :
>>> If case class inheritance goes away, I'm going to have to duplicate that
>>> noisy, non-semantic logic throughout all the places in my AST where I was
>>> previously using case class inheritance. While "it seems not so bad" in one
>>> isolated case in one isolated place, having to use that idiom repetitively
>>> is going to get very tiring very quickly.
>>>
>>> Maybe I'm just going the wrong way? What I'm trying to do is mimic OCaml's
>>> variant types to represent my AST, so that walking the tree is a bunch of
>>> recursive pattern matching, and my implementation is checked for
>>> completeness by the compiler.
>>>
>>> In OCaml, it'd be something like this:
>>> # type intvalue = Int of int;;
>>> # type stringvalue = Rich of string | Literal of string;;
>>> # type csvalue = StringValue of stringvalue | IntValue of intvalue;;
>> So, this doesn't seem to need case class inheritance to emulate,
>> unless I'm missing something. You can introduce abstract classes (or
>> traits) into the tree without a problem.
>>
>> The only thing you lose in having the following:
>>
>> sealed abstract class CSValue extends Positional
>> sealed case class CSTuple(elements:List[Expression]) extends CSValue
>> sealed class StringValue(value:String) extends CSValue // not a case class
>> sealed case class LiteralStringValue(myValue:String) extends
>> StringValue(myValue)
>> sealed case class RichStringValue(pattern:String) extends StringValue(myValue)
>>
>> Is that you have to match on StringValue as
>>
>> case (x : StringValue) => doStuffWith(x.value);
>>
>> instead of
>>
>> case StringValue(value) => doStuffWith(value)
>>
>> This is certainly a little unfortunate (particularly given the
>> increased difficulty of nesting patterns), but seems to offer
>> equivalent functionality to the OCaml version (if what little I know
>> of OCaml pattern matching is accurate).
>>
> Or one could define an extractor for StringValue to do it this way. I.e:
>
> object StringValue {
> def unapply(x: StringValue) = Some(x.value)
> }
>
> Given that currently matches against inheriting case classes are done with
> extractors anyway, that would not be a large change. It does make
> programming this sort of nested hierarchies more difficult (need to
> know about extractors). On the other hand, we are still within Alan
> Kay's postulate to make simple things easy and difficult things
> possible.
>
> Cheers
>
Fri, 2009-04-24, 15:57
#14
Re: Do you use case class inheritance?
On Fri, Apr 24, 2009 at 3:47 PM, Robert Fischer
wrote:
> Spewing a whole series of unapply definitions is really unpalatable -- I'm
> inheriting all over my AST structure, so I'm going to have to use that
> completely non-semantic boilerplate idiom a dozen times or so. I'm not a
> huge fan.
>
> James Iry's composition approach seems to be a lot nicer:
>
> sealed abstract class stringvalue
> sealed case class Rich(x : String) extends stringvalue
> sealed case class Literal(x : String) extends stringvalue
>
> sealed abstract class CSValue
> sealed case class IntValue(x : Int) extends CSValue
> sealed case class StringValue(x : stringvalue) extends CSValue
>
> I'm still having to introduce a noise type in there to make the type system
> work, but it gives me basically the same functionality (modulo some
> additional noise in a flattened match) without having to remember/read
> through the syntax for unapply.
>
> Is there an issue with that approach I'm not seeing?
>
I don't think so. It shifts the load from havintg to define extractors
to tree construction and matching. So in the end it will depend how
often you do each sort of thing.
Cheers
>>>>> "Erkki" == Erkki Lindpere writes:
Erkki> I use it to describe rules in a popular card game which has
Erkki> extremely complex rules (I won't name it because I'm not sure
Erkki> where this project will go or if it will go anywhere at
Erkki> all). But I have found them useful. I do use case classes MOSTLY
Erkki> in Leaves, but for convenience I sometimes use deeper
Erkki> hierarchies, sometimes case objects that extend case classes.
Erkki> The best reason I can give is that it's easier to construct
Erkki> expressions/sentences if I use more specific case
Erkki> classes/objects, but when executing the expressions (with
Erkki> pattern matching), I don't care about some of the leaf classes
Erkki> (leafs are for convenience when constructing the expressions).
It sounds like the leaf objects don't really need to be case objects,
then? After all you can do e.g.:
case class A(x:Int)
object B extends A(3)