This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Abstract Types question

9 replies
oscar.forero
Joined: 2009-08-20,
User offline. Last seen 2 years 32 weeks ago.
Hello,   Sorry for keep hammering the same topic, but I still have some issues with my reimplementation from a internal Java library. I want to have encapsulated numeric values that can support different operations, some times addition and subtraction, others the whole set, etc.   Here is what I have:   abstract class SimpleValue {
    type S <: SimpleValue
    type V <: {
        def +(other: V): V
    }       protected val value: V       protected implicit def T2SimpleValue(ret: V): S
   
    //protected def *(other: V):S =
    protected def +(other: S): S = value + other.value.asInstanceOf[V]
    //protected def -(other: V):S =
}   trait Plus {
    type S <: SimpleValue       def +(other: S): S = this + other
}   class IntValue(protected val value: Int) extends SimpleValue {
    type S = IntValue
    type V = Int
}   class Shares(value: Int) extends IntValue(value) with Plus
Besides the construction difficulties that some in the list already addressed in a previous question, I have one further problem:   $ NumericValue.scala:13: error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement
        def +(other: V): V   But pretty much all numbers have such operations, I want V to be limited to classes that have a plus method that takes a parameter of the same type and returns the same type, that really seems like a legitimate structural type to me, I try to do something like:       type V <: {         type O
        def +(other: O): O
    }   But then I have no idea how to declare the concrete type of O, it seem that this will require the class I assign to V to declare a type O which is not what I want. Is there any way in which this kind of structural refinments could be expressed?   regards,   Oscar

**********************************************************************

Please consider the environment before printing this email or its attachments.

The contents of this email are for the named addressees only. It contains information which may be confidential and privileged. If you are not the intended recipient, please notify the sender immediately, destroy this email and any attachments and do not otherwise disclose or use them. Email transmission is not a secure method of communication and Man Investments cannot accept responsibility for the completeness or accuracy of this email or any attachments. Whilst Man Investments makes every effort to keep its network free from viruses, it does not accept responsibility for any computer virus which might be transferred by way of this email or any attachments. This email does not constitute a request, offer, recommendation or solicitation of any kind to buy, subscribe, sell or redeem any investment instruments or to perform other such transactions of any kind. Man Investments reserves the right to monitor, record and retain all electronic communications through its network to ensure the integrity of its systems, for record keeping and regulatory purposes.

Visit us at: www.maninvestments.com

TG0908

**********************************************************************

 

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 19 hours ago.
Re: Abstract Types question

Hi Oscar,

you should really try (and in many cases it is possible) to refrain
from using structural types. You might have a valid use-case indeed
but you should try to state your use-case in a clean and concise form
if you want to improve your chances of someone replying to your
questions.

The previous hint with the Numeric classes in Scala 2.8 is a good one.
Here's a link to the current implementation on trunk:
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala...
, if you don't want to wait for 2.8 you can easily roll your own
scheme in the same manner.

Perhaps someone can reply with some usage examples for Numeric. And
IIRC there was a blog post in the past which explained exactly this
concept.

Kevin Wright
Joined: 2009-06-09,
User offline. Last seen 49 weeks 3 days ago.
Re: Abstract Types question
+1
The structural type you are trying to define here would also match lists and strings... Is that really what you're trying to achieve?

On Fri, Aug 21, 2009 at 11:59 AM, Johannes Rudolph <johannes [dot] rudolph [at] googlemail [dot] com> wrote:
Hi Oscar,

you should really try (and in many cases it is possible) to refrain
from using structural types. You might have a valid use-case indeed
but you should try to state your use-case in a clean and concise form
if you want to improve your chances of someone replying to your
questions.

The previous hint with the Numeric classes in Scala 2.8 is a good one.
Here's a link to the current implementation on trunk:
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala/Numeric.scala
, if you don't want to wait for 2.8 you can easily roll your own
scheme in the same manner.

Perhaps someone can reply with some usage examples for Numeric. And
IIRC there was a blog post in the past which explained exactly this
concept.

--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

oscar.forero
Joined: 2009-08-20,
User offline. Last seen 2 years 32 weeks ago.
RE: Abstract Types question

Hello Johannes,

Thanks for the answer, I would like to ask you why should we refrain
from structural types? are they slow?

I found an explanation for this error it has to do with the way
structural types where implemented and type erasure that the JVM
imposes: http://markmail.org/message/tzoq46blvlcux4ip

I kind of work around the problem but with the price of more code, now I
will have to define resolved classes for Long, Double, BigDecimal, etc.
but I can have numeric types that support only some operations not all.

In the example object at the end the last line is not compliable which
is what I wanted to achieve, the ideas is for example that a price per
share can be multiplied to a number of shares but not to anything else.

The next refinement will be to use Path dependant types to restrict that
operation to shares and price per share of the same company/fund/etc.

protected[util] abstract class SimpleValue[V](protected[util] val value:
V) {

type S <: SimpleValue[V]

protected implicit def T2SimpleValue(ret: V): S
protected def plus(arg0: V, arg1: V): V
protected def minus(arg0: V, arg1: V): V
protected def times(arg0: V, arg1: V): V
protected def divide(arg0: V, arg1: V): V

override def toString = "" + getClass + " = " + value
}

trait Addition[V] {
self: SimpleValue[V] =>
def +(other: S): S = plus(this.value, other.value)
}

trait Subtraction[V] {
self: SimpleValue[V] =>
def -(other: S): S = minus(this.value, other.value)
}

trait Multiplication[V] {
self: SimpleValue[V] =>
def *(other: S): S = times(this.value, other.value)
}

trait Division[V] {
self: SimpleValue[V] =>
def /(other: S): S = divide(this.value, other.value)
}

abstract class IntValue(value: Int) extends SimpleValue[Int](value) {
type V = Int
type S = IntValue

protected def plus(arg0: Int, arg1: Int): Int = arg0 + arg1
protected def minus(arg0: Int, arg1: Int): Int = arg0 - arg1
protected def times(arg0: Int, arg1: Int): Int = arg0 * arg1
protected def divide(arg0: Int, arg1: Int): Int = arg0 / arg1
}

class Shares(value: Int) extends IntValue(value) with Addition[Int] with
Subtraction[Int] {
protected implicit def T2SimpleValue(ret: Int): S = new Shares(ret)
}

object Example {

def main(args: Array[String]) :Unit = {
val shares1 = new Shares(2000)
val shares2 = new Shares(3000)

println(shares1)
println(shares2)
println("Add ==> " + (shares1 + shares2))
println("Sub ==> " + (shares1 - shares2))
println("Mult ==> " + (shares1 * shares2))

}
}

-----Original Message-----
From: Johannes Rudolph [mailto:johannes [dot] rudolph [at] googlemail [dot] com]
Sent: Freitag, 21. August 2009 13:00
To: Forero, Oscar (Pfaeffikon)
Cc: scala-user [at] listes [dot] epfl [dot] ch
Subject: Re: [scala-user] Abstract Types question

Hi Oscar,

you should really try (and in many cases it is possible) to refrain from
using structural types. You might have a valid use-case indeed but you
should try to state your use-case in a clean and concise form if you
want to improve your chances of someone replying to your questions.

The previous hint with the Numeric classes in Scala 2.8 is a good one.
Here's a link to the current implementation on trunk:
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala
/Numeric.scala
, if you don't want to wait for 2.8 you can easily roll your own scheme
in the same manner.

Perhaps someone can reply with some usage examples for Numeric. And IIRC
there was a blog post in the past which explained exactly this concept.

--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

**********************************************************************
Please consider the environment before printing this email or its attachments.
The contents of this email are for the named addressees only. It contains information which may be confidential and privileged. If you are not the intended recipient, please notify the sender immediately, destroy this email and any attachments and do not otherwise disclose or use them. Email transmission is not a secure method of communication and Man Investments cannot accept responsibility for the completeness or accuracy of this email or any attachments. Whilst Man Investments makes every effort to keep its network free from viruses, it does not accept responsibility for any computer virus which might be transferred by way of this email or any attachments. This email does not constitute a request, offer, recommendation or solicitation of any kind to buy, subscribe, sell or redeem any investment instruments or to perform other such transactions of any kind. Man Investments reserves the right to monitor, record and retain all electronic communications through its network to ensure the integrity of its systems, for record keeping and regulatory purposes.
Visit us at: www.maninvestments.com
TG0908
**********************************************************************

oscar.forero
Joined: 2009-08-20,
User offline. Last seen 2 years 32 weeks ago.
RE: Abstract Types question
Hello,   No that was not the intent, this was just a test of what is possible. Provided that work I wanted to add - * /, would prefer to do something like V <: Numeric but Int, Long, Double, and BigDecimal do not extend from the same trait and the new Numeric trait appears to be a complete separate hierarchy.   Because they do not have a common super class where those operations are defined I thought to do it structural types, but that does not work with methods that use the same type that is being abstracted by the structural type ... :-(   Thanks for your response,   Oscar
From: Kevin Wright [mailto:kev [dot] lee [dot] wright [at] googlemail [dot] com]
Sent: Freitag, 21. August 2009 13:07
To: Johannes Rudolph
Cc: Forero, Oscar (Pfaeffikon); scala-user [at] listes [dot] epfl [dot] ch
Subject: Re: [scala-user] Abstract Types question

+1
The structural type you are trying to define here would also match lists and strings... Is that really what you're trying to achieve?

On Fri, Aug 21, 2009 at 11:59 AM, Johannes Rudolph <johannes [dot] rudolph [at] googlemail [dot] com> wrote:
Hi Oscar,

you should really try (and in many cases it is possible) to refrain
from using structural types. You might have a valid use-case indeed
but you should try to state your use-case in a clean and concise form
if you want to improve your chances of someone replying to your
questions.

The previous hint with the Numeric classes in Scala 2.8 is a good one.
Here's a link to the current implementation on trunk:
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala/Numeric.scala
, if you don't want to wait for 2.8 you can easily roll your own
scheme in the same manner.

Perhaps someone can reply with some usage examples for Numeric. And
IIRC there was a blog post in the past which explained exactly this
concept.

--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

**********************************************************************

Please consider the environment before printing this email or its attachments.

The contents of this email are for the named addressees only. It contains information which may be confidential and privileged. If you are not the intended recipient, please notify the sender immediately, destroy this email and any attachments and do not otherwise disclose or use them. Email transmission is not a secure method of communication and Man Investments cannot accept responsibility for the completeness or accuracy of this email or any attachments. Whilst Man Investments makes every effort to keep its network free from viruses, it does not accept responsibility for any computer virus which might be transferred by way of this email or any attachments. This email does not constitute a request, offer, recommendation or solicitation of any kind to buy, subscribe, sell or redeem any investment instruments or to perform other such transactions of any kind. Man Investments reserves the right to monitor, record and retain all electronic communications through its network to ensure the integrity of its systems, for record keeping and regulatory purposes.

Visit us at: www.maninvestments.com

TG0908

**********************************************************************

 

Kevin Wright
Joined: 2009-06-09,
User offline. Last seen 49 weeks 3 days ago.
Re: Abstract Types question


On Fri, Aug 21, 2009 at 12:57 PM, Forero, Oscar (Pfaeffikon) <oforero [at] maninvestments [dot] com> wrote:
Hello Johannes,

Thanks for the answer, I would like to ask you why should we refrain
from structural types? are they slow?

I found an explanation for this error it has to do with the way
structural types where implemented and type erasure that the JVM
imposes: http://markmail.org/message/tzoq46blvlcux4ip
 Sadly, structural types _are_ slow.  they have got faster since first conceived, but reflection and (Un)Boxing really aren't your friends here :(
Out of curiosity, are you working with 2.7 or 2.8
oscar.forero
Joined: 2009-08-20,
User offline. Last seen 2 years 32 weeks ago.
RE: Abstract Types question
Hello,   I was on 2.7.5 but just installed the latest 2.8, is there anything there that may help? somebody pointed out to the new Numeric Trait but that will be probably achieved with a implicit conversion if can be used to get all numbers by using a view bound which is like boxing isn't?   regards,   Oscar
From: Kevin Wright [mailto:kev [dot] lee [dot] wright [at] googlemail [dot] com]
Sent: Freitag, 21. August 2009 14:27
To: Forero, Oscar (Pfaeffikon)
Cc: scala-user [at] listes [dot] epfl [dot] ch
Subject: Re: [scala-user] Abstract Types question



On Fri, Aug 21, 2009 at 12:57 PM, Forero, Oscar (Pfaeffikon) <oforero [at] maninvestments [dot] com> wrote:
Hello Johannes,

Thanks for the answer, I would like to ask you why should we refrain
from structural types? are they slow?

I found an explanation for this error it has to do with the way
structural types where implemented and type erasure that the JVM
imposes: http://markmail.org/message/tzoq46blvlcux4ip
  Sadly, structural types _are_ slow.  they have got faster since first conceived, but reflection and (Un)Boxing really aren't your friends here :(
Out of curiosity, are you working with 2.7 or 2.8

**********************************************************************

Please consider the environment before printing this email or its attachments.

The contents of this email are for the named addressees only. It contains information which may be confidential and privileged. If you are not the intended recipient, please notify the sender immediately, destroy this email and any attachments and do not otherwise disclose or use them. Email transmission is not a secure method of communication and Man Investments cannot accept responsibility for the completeness or accuracy of this email or any attachments. Whilst Man Investments makes every effort to keep its network free from viruses, it does not accept responsibility for any computer virus which might be transferred by way of this email or any attachments. This email does not constitute a request, offer, recommendation or solicitation of any kind to buy, subscribe, sell or redeem any investment instruments or to perform other such transactions of any kind. Man Investments reserves the right to monitor, record and retain all electronic communications through its network to ensure the integrity of its systems, for record keeping and regulatory purposes.

Visit us at: www.maninvestments.com

TG0908

**********************************************************************

 

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 19 hours ago.
Re: Abstract Types question

On Fri, Aug 21, 2009 at 1:57 PM, Forero, Oscar
(Pfaeffikon) wrote:
> Thanks for the answer, I would like to ask you why should we refrain
> from structural types? are they slow?
Because structural types are actually selected 'by name' they are
called by reflection which has to be slower than direct calling. That
said, it might be that they will be faster in the future. New features
coming to the JDK in the next time could lessen the cost in the
future. I'm thinking of MethodHandles/invokedynamic here. Don't know
if anyone has looked into that yet.

Regarding your example, this works as you requested (before Scala 2.8
you have to define one implicit per Numeric):

object Test {
trait Numeric[T]{
def plus(t1:T,t2:T):T
def minus(t1:T,t2:T):T
def times(t1:T,t2:T):T
}

trait ValueHolder[T,S]{
def value:T
def create(v:T):S
}

// to simplify creation
case class VHolderImpl[T,S](v:T,cons:T=>S) extends ValueHolder[T,S]{
def value = v
def create(v:T):S = cons(v)
}

trait Addition[T,S<:ValueHolder[T,S]]{
self: ValueHolder[T,S] =>
def +(other:S)(implicit num:Numeric[T]):S =
create(num.plus(value,other.value))
}

case class Shares(num:Int) extends VHolderImpl[Int,Shares](num,Shares(_))
with Addition[Int,Shares]

implicit object IntNumeric extends Numeric[Int]{
def plus(t1:Int,t2:Int):Int = t1 + t2
def minus(t1:Int,t2:Int):Int = t1 - t2
def times(t1:Int,t2:Int):Int = t1 * t2
}

val sum:Shares = Shares(1) + Shares(2)
Shares(2) * Shares(2) // fails
}

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 19 hours ago.
Re: Abstract Types question

On Fri, Aug 21, 2009 at 2:36 PM, Forero, Oscar
(Pfaeffikon) wrote:
> Hello,
>
> I was on 2.7.5 but just installed the latest 2.8, is there anything there
> that may help? somebody pointed out to the new Numeric Trait but that will
> be probably achieved with a implicit conversion if can be used to get all
> numbers by using a view bound which is like boxing isn't?
Yes it works with implicits/view bounds but no, this is not like
boxing, since no additional object is necessary (the actual implicits
are implicit singleton objects). As you can see in this disassembly
snippet the overhead is basiccaly a static field load which is passed
to the function:

25: getstatic #31; //Field Test$IntNumeric$.MODULE$:LTest$IntNumeric$;
28: invokeinterface #37, 3; //InterfaceMethod
Test$Addition.$plus:(LTest$ValueHolder;LTest$Numeric;)LTest$ValueHolder;

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 19 hours ago.
Re: Abstract Types question

On Fri, Aug 21, 2009 at 2:42 PM, Johannes
Rudolph wrote:
22: invokespecial #26; //Method Test$Shares."":(I)V
>   25:  getstatic       #31; //Field Test$IntNumeric$.MODULE$:LTest$IntNumeric$;
>   28:  invokeinterface #37,  3; //InterfaceMethod Test$Addition.$plus:(LTest$ValueHolder;LTest$Numeric;)LTest$ValueHolder;
BTW: Does anyone know why the scala compiler generates an
'invokeinterface' here instead of 'invokevirtual' even if the concrete
type in this case is known? This seems wasteful. In theory
invokeinterface is slower than invokevirtual, at least if the actual
type hierarchy is known (and the class in question has no subclasses),
so that a invokevirtual in fact becomes a static call saving one layer
of indirection.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland