- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Type refinement in subclass question
Tue, 2012-01-31, 20:29
I'm trying to refine a type within a subclass (where TextElement is a subclass of Element):
abstract class Mark { var element: Option[_ <: Element]; }
class TextMark extends Mark { var element: Option[TextElement] = None }
but this doesn't work as the compiler doesn't see the subclass declaration as being a refinement of the superclass declaration.
Next attempt:
abstract class Mark { type ElementType <: Element var element: Option[ElementType]; }
class TextMark extends Mark { type ElementType = TextElement var element: Option[ElementType] = None }
This is closer, but still no go, due to, it appears, the fact that ElementType has a different type path than Element/TextElement.
Conceptually, an element is a holder of data, and a mark is an offset denoting a location in that data; all elements support a certain set of operation, while specific subtypes support further operations. Marks are used to perform operations on data at the positions the marks indicate. The goal is to be able to state this so that any Mark instance can be operated on with operations that are common to all element types.
I'm not so much looking for a "correct" typing, as that will depend on exactly what I decide should be the semantics of the situation. I'm more interested in learning how best to handle cases such as this. Pointers to good tutorials/exercises/explanations relating to this are certainly appreciated.
Thanks,Ken
abstract class Mark { var element: Option[_ <: Element]; }
class TextMark extends Mark { var element: Option[TextElement] = None }
but this doesn't work as the compiler doesn't see the subclass declaration as being a refinement of the superclass declaration.
Next attempt:
abstract class Mark { type ElementType <: Element var element: Option[ElementType]; }
class TextMark extends Mark { type ElementType = TextElement var element: Option[ElementType] = None }
This is closer, but still no go, due to, it appears, the fact that ElementType has a different type path than Element/TextElement.
Conceptually, an element is a holder of data, and a mark is an offset denoting a location in that data; all elements support a certain set of operation, while specific subtypes support further operations. Marks are used to perform operations on data at the positions the marks indicate. The goal is to be able to state this so that any Mark instance can be operated on with operations that are common to all element types.
I'm not so much looking for a "correct" typing, as that will depend on exactly what I decide should be the semantics of the situation. I'm more interested in learning how best to handle cases such as this. Pointers to good tutorials/exercises/explanations relating to this are certainly appreciated.
Thanks,Ken
Tue, 2012-01-31, 23:31
#2
Re: Type refinement in subclass question
What you are experiencing is type safety in action. Because refining vars is inherently unsafe.
Lets assume that class TextMark compiles, then:
abstract class Mark { var element: Option[_ <: Element]; }
class TextMark extends Mark { var element: Option[TextElement] = None }
val mark: Mark = new TextMark
class OtherElement extends Element
mark.element = Some(new OtherElement)
The value mark is an instance of TextMark, but mark.element is Option[OtherElement]. However TextMark.element is defined as Option[TextElement]. So we have a violation of the type system.
On Tue, Jan 31, 2012 at 1:29 PM, Ken McDonald <ykkenmcd@gmail.com> wrote:
Lets assume that class TextMark compiles, then:
abstract class Mark { var element: Option[_ <: Element]; }
class TextMark extends Mark { var element: Option[TextElement] = None }
val mark: Mark = new TextMark
class OtherElement extends Element
mark.element = Some(new OtherElement)
The value mark is an instance of TextMark, but mark.element is Option[OtherElement]. However TextMark.element is defined as Option[TextElement]. So we have a violation of the type system.
On Tue, Jan 31, 2012 at 1:29 PM, Ken McDonald <ykkenmcd@gmail.com> wrote:
I'm trying to refine a type within a subclass (where TextElement is a subclass of Element):
abstract class Mark { var element: Option[_ <: Element]; }
class TextMark extends Mark { var element: Option[TextElement] = None }
but this doesn't work as the compiler doesn't see the subclass declaration as being a refinement of the superclass declaration.
Next attempt:
abstract class Mark { type ElementType <: Element var element: Option[ElementType]; }
class TextMark extends Mark { type ElementType = TextElement var element: Option[ElementType] = None }
This is closer, but still no go, due to, it appears, the fact that ElementType has a different type path than Element/TextElement.
Conceptually, an element is a holder of data, and a mark is an offset denoting a location in that data; all elements support a certain set of operation, while specific subtypes support further operations. Marks are used to perform operations on data at the positions the marks indicate. The goal is to be able to state this so that any Mark instance can be operated on with operations that are common to all element types.
I'm not so much looking for a "correct" typing, as that will depend on exactly what I decide should be the semantics of the situation. I'm more interested in learning how best to handle cases such as this. Pointers to good tutorials/exercises/explanations relating to this are certainly appreciated.
Thanks,Ken
Wed, 2012-02-01, 00:21
#3
Re: Type refinement in subclass question
Maybe the error message could be more explain more, because it hints
in another direction
e.g.
"error: type unsafe var refinement is not allowed here."
On 31 jan, 23:24, Aleksey Nikiforov wrote:
> What you are experiencing is type safety in action. Because refining vars
> is inherently unsafe.
> Lets assume that class TextMark compiles, then:
>
> abstract class Mark { var element: Option[_ <: Element]; }
> class TextMark extends Mark { var element: Option[TextElement] = None }
>
> val mark: Mark = new TextMark
>
> class OtherElement extends Element
> mark.element = Some(new OtherElement)
>
> The value mark is an instance of TextMark, but mark.element is
> Option[OtherElement]. However TextMark.element is defined as
> Option[TextElement]. So we have a violation of the type system.
>
>
>
> On Tue, Jan 31, 2012 at 1:29 PM, Ken McDonald wrote:
> > I'm trying to refine a type within a subclass (where TextElement is a
> > subclass of Element):
>
> > abstract class Mark { var element: Option[_ <: Element]; }
>
> > class TextMark extends Mark { var element: Option[TextElement] = None }
>
> > but this doesn't work as the compiler doesn't see the subclass declaration
> > as being a refinement of the superclass declaration.
>
> > Next attempt:
>
> > abstract class Mark {
> > type ElementType <: Element
> > var element: Option[ElementType];
> > }
>
> > class TextMark extends Mark {
> > type ElementType = TextElement
> > var element: Option[ElementType] = None
> > }
>
> > This is closer, but still no go, due to, it appears, the fact that
> > ElementType has a different type path than Element/TextElement.
>
> > Conceptually, an element is a holder of data, and a mark is an offset
> > denoting a location in that data; all elements support a certain set of
> > operation, while specific subtypes support further operations. Marks are
> > used to perform operations on data at the positions the marks indicate. The
> > goal is to be able to state this so that any Mark instance can be operated
> > on with operations that are common to all element types.
>
> > I'm not so much looking for a "correct" typing, as that will depend on
> > exactly what I decide should be the semantics of the situation. I'm more
> > interested in learning how best to handle cases such as this. Pointers to
> > good tutorials/exercises/explanations relating to this are certainly
> > appreciated.
>
> > Thanks,
> > Ken- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Looks like a bug or maybe an intended limitation for other reasons
e.g. initialization problems.
Otherwise I don't see why there is a difference between refining and
then defining vars and vals in a subclass of an abstract class.
Or I missed something.
Refinement
==========
only vals can be refined and then defined in a subclass
refining vars and then defining them raises an error
scala> abstract class Mark { var element: Option[_ <: Element] }
defined class Mark
scala> class TextMark extends Mark { var element: Option[TextElement]
= None}
:10: error: class TextMark needs to be abstract, since
variable element
in class Mark of type Option[_ <: Element] is not defined
(Note that an abstract var requires a setter in addition to the
getter)
class TextMark extends Mark { var element: Option[TextElement]
= None}
^
scala> abstract class Mark { val element: Option[_ <: Element] }
defined class Mark
scala> class TextMark extends Mark { val element: Option[TextElement]
= None}
defined class TextMark
scala> abstract class A { var x : AnyVal }
defined class A
scala> class B extends A { var x : Int = 2 }
:8: error: class B needs to be abstract, since variable x in
class A of
type AnyVal is not defined
(Note that an abstract var requires a setter in addition to the
getter)
class B extends A { var x : Int = 2 }
^
scala> abstract class A { val x : AnyVal }
defined class A
scala> class B extends A { val x : Int = 2 }
defined class B
No refinement, just defining
============================
vars or vals can be defined in subclass
scala> abstract class A { var x: Int }
defined class A
scala> class B extends A { var x = 2 }
defined class B
scala> abstract class A { val x: Int }
defined class A
scala> class B extends A { val x = 2 }
defined class B
On 31 jan, 20:29, Ken McDonald wrote:
> I'm trying to refine a type within a subclass (where TextElement is a
> subclass of Element):
>
> abstract class Mark { var element: Option[_ <: Element]; }
>
> class TextMark extends Mark { var element: Option[TextElement] = None }
>
> but this doesn't work as the compiler doesn't see the subclass declaration
> as being a refinement of the superclass declaration.
>
> Next attempt:
>
> abstract class Mark {
> type ElementType <: Element
> var element: Option[ElementType];
> }
>
> class TextMark extends Mark {
> type ElementType = TextElement
> var element: Option[ElementType] = None
> }
>
> This is closer, but still no go, due to, it appears, the fact that
> ElementType has a different type path than Element/TextElement.
>
> Conceptually, an element is a holder of data, and a mark is an offset
> denoting a location in that data; all elements support a certain set of
> operation, while specific subtypes support further operations. Marks are
> used to perform operations on data at the positions the marks indicate. The
> goal is to be able to state this so that any Mark instance can be operated
> on with operations that are common to all element types.
>
> I'm not so much looking for a "correct" typing, as that will depend on
> exactly what I decide should be the semantics of the situation. I'm more
> interested in learning how best to handle cases such as this. Pointers to
> good tutorials/exercises/explanations relating to this are certainly
> appreciated.
>
> Thanks,
> Ken