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

Manifest, implicits and apply for DSL

28 replies
Roman Roelofsen
Joined: 2009-03-03,
User offline. Last seen 42 years 45 weeks ago.

Dear Scala Fellows!

In a Scala DSL, I want to be able to write

withClass [String]

and

withClass [String] {
// ...
}

I want avoid to write classOf[...] all the time. The first one is
quite easy to implement:

def withClass[A](implicit clazz: scala.reflect.Manifest[A])

However, I have some trouble solving the 2nd one. I tried the
following solutions, none of them worked:

(1) Overloading the withClass method

def withClass[A](implicit clazz: scala.reflect.Manifest[A])
def withClass[A](block: => Unit)(implicit clazz: scala.reflect.Manifest[A])

When calling without the block, the Scala compiler does not know it I
want to call the non-block method or if I want to partially apply the
with-block method.

(2) Returning an object with an apply method
class Helper {
def apply(block: => Unit) = {...}
}
def withClass[A](implicit clazz: scala.reflect.Manifest[A]) = {
new Helper
}

When I try to pass the block, the scala compiler thinks that I want to
pass the block as the scala.reflect.Manifest parameter. Directly
calling apply works:

withClass [String].apply {
// ...
}

What else can I do?

Cheers,

Roman

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: Manifest, implicits and apply for DSL
3) Use different method names.

On Fri, Mar 6, 2009 at 3:37 PM, Roman Roelofsen <roman.roelofsen@googlemail.com> wrote:
Dear Scala Fellows!

In a Scala DSL, I want to be able to write

withClass [String]

and

withClass [String] {
 // ...
}

I want avoid to write classOf[...] all the time. The first one is
quite easy to implement:

def withClass[A](implicit clazz: scala.reflect.Manifest[A])

However, I have some trouble solving the 2nd one. I tried the
following solutions, none of them worked:

(1) Overloading the withClass method

def withClass[A](implicit clazz: scala.reflect.Manifest[A])
def withClass[A](block: => Unit)(implicit clazz: scala.reflect.Manifest[A])

When calling without the block, the Scala compiler does not know it I
want to call the non-block method or if I want to partially apply the
with-block method.


(2) Returning an object with an apply method
class Helper {
 def apply(block: => Unit) = {...}
}
def withClass[A](implicit clazz: scala.reflect.Manifest[A]) = {
 new Helper
}

When I try to pass the block, the scala compiler thinks that I want to
pass the block as the scala.reflect.Manifest parameter. Directly
calling apply works:

withClass [String].apply {
 // ...
}

What else can I do?

Cheers,

Roman

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 3 days ago.
Re: Manifest, implicits and apply for DSL
Actually, there may be an option 4) wait for Default Arguments (https://lampsvn.epfl.ch/trac/scala/export/16712/lamp-sip/named-args/sip.xhtml)

Though even then the syntax would not be exactly as you'd like.

--j

On Sun, Mar 8, 2009 at 9:19 PM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
3) Use different method names.

On Fri, Mar 6, 2009 at 3:37 PM, Roman Roelofsen <roman.roelofsen@googlemail.com> wrote:
Dear Scala Fellows!

In a Scala DSL, I want to be able to write

withClass [String]

and

withClass [String] {
 // ...
}

I want avoid to write classOf[...] all the time. The first one is
quite easy to implement:

def withClass[A](implicit clazz: scala.reflect.Manifest[A])

However, I have some trouble solving the 2nd one. I tried the
following solutions, none of them worked:

(1) Overloading the withClass method

def withClass[A](implicit clazz: scala.reflect.Manifest[A])
def withClass[A](block: => Unit)(implicit clazz: scala.reflect.Manifest[A])

When calling without the block, the Scala compiler does not know it I
want to call the non-block method or if I want to partially apply the
with-block method.


(2) Returning an object with an apply method
class Helper {
 def apply(block: => Unit) = {...}
}
def withClass[A](implicit clazz: scala.reflect.Manifest[A]) = {
 new Helper
}

When I try to pass the block, the scala compiler thinks that I want to
pass the block as the scala.reflect.Manifest parameter. Directly
calling apply works:

withClass [String].apply {
 // ...
}

What else can I do?

Cheers,

Roman


Andreas W
Joined: 2009-01-10,
User offline. Last seen 1 year 14 weeks ago.
Flagging Uniques

Scalars,

Behold the following code for finding a an array of Booleans that flag the first unique occurrence of each element of a sequence:

      val seq: Seq[T]
      val set = new HashSet[T]
      val unique = for (v<-seq) yield if (set.contains(v)) false else { set += v; true }

It works, and is reasonably concise, but not exactly elegant. Just look at that ugly mutable set!

What would be a more functional way to do this? I have tried some ideas, but none came out more elegant than the above.

Andreas


Alex Boisvert
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: Flagging Uniques
What you're doing is essentially a fold with a List[Boolean] and a Set[T] as carryover... both of which can be immutable.

case class Carry[T](val list: List[Boolean], val set: Set[T])

val seq: Seq[Int] = List(1,2,3,1,2,3)

seq.foldLeft(Carry(Nil, Set[Int]())) { (carry, x) =>
  Carry(!carry.set.contains(x) :: carry.list, carry.set + x)
}.list.reverse

result: List[Boolean] = List(true, true, true, false, false, false)

alex


On Tue, Mar 10, 2009 at 8:41 AM, Windemuth Andreas <windemut@yahoo.com> wrote:

Scalars,

Behold the following code for finding a an array of Booleans that flag the first unique occurrence of each element of a sequence:

      val seq: Seq[T]
      val set = new HashSet[T]
      val unique = for (v<-seq) yield if (set.contains(v)) false else { set += v; true }

It works, and is reasonably concise, but not exactly elegant. Just look at that ugly mutable set!

What would be a more functional way to do this? I have tried some ideas, but none came out more elegant than the above.

Andreas



Jesper Nordenberg
Joined: 2008-12-27,
User offline. Last seen 42 years 45 weeks ago.
Re: Flagging Uniques

Windemuth Andreas wrote:
>
> Scalars,
>
> Behold the following code for finding a an array of Booleans that flag
> the first unique occurrence of each element of a sequence:
>
> val seq: Seq[T]
> val set = new HashSet[T]
> val unique = for (v<-seq) yield if (set.contains(v)) false else {
> set += v; true }
>
> It works, and is reasonably concise, but not exactly elegant. Just look
> at that ugly mutable set!
>
> What would be a more functional way to do this? I have tried some ideas,
> but none came out more elegant than the above.

Not very elegant and probably slow as hell, but it's stateless:

seq.foldLeft((new HashSet : Set[T], List[Boolean]()))((t, value) => if
(t._1.contains(value)) (t._1, false :: t._2) else (t._1 + value, true ::
t._2))._2.reverse

/Jesper Nordenberg

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Flagging Uniques

On Tue, Mar 10, 2009 at 09:43:43AM -0700, Alex Boisvert wrote:
> What you're doing is essentially a fold with a List[Boolean] and a
> Set[T] as carryover... both of which can be immutable.

Alex was faster, but since I just wrote the one liner I have to send it:

scala> val xs = List("a", "b", "c", "b", "a", "c", "d", "b")
xs: List[java.lang.String] = List(a, b, c, b, a, c, d, b)
scala> xs.foldLeft(List[(String, Boolean)]())((l, e) => (e, !l.map(_._1).contains(e)) :: l).reverseMap(_._2)
res1: List[Boolean] = List(true, true, true, false, false, false, true, false)

Jan Kriesten
Joined: 2009-01-13,
User offline. Last seen 2 years 39 weeks ago.
Re: Flagging Uniques

Hi Andreas,

just playing around giving another solution:

def flagSeq[T]( s: Seq[T] ): List[Boolean] = {
def loop( e: T, s: Seq[T] ): List[Boolean] = (if( s.isEmpty ) List(true) else
loop(s.first, s.drop(1)) + !s.contains(e))
val sRev = s.reverse
loop( sRev.first, sRev.drop(1) )
}

val seq: Seq[Int] = List(1,2,4,2,5,1,5)

val x = flagSeq( seq )

The difference is that I'm reversing the List first and look if the element is
contained in the tail. Though it's not yet tail-recursive...

Regards, --- Jan.

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Flagging Uniques

On Tue, Mar 10, 2009 at 08:41:33AM -0700, Windemuth Andreas wrote:
> What would be a more functional way to do this? I have tried some
> ideas, but none came out more elegant than the above.

OK, this is better. It would look so much prettier if type inference on
Nil could cast its gaze a little bit forward.

xs./:(List[Boolean](), Set[String]())((ls, e) =>
(!ls._2.contains(e) :: ls._1, ls._2 + e))._1.reverse

Imaginary version requiring both additional sugar for tuples as
parameters and slightly non-local inference:

xs /: (Nil, Nil) (((l1, l2), e) => (!l2.contains(e) :: l1, l2 + e)._1.reverse

Frohnhofer, James
Joined: 2009-03-10,
User offline. Last seen 42 years 45 weeks ago.
RE: Flagging Uniques

Slow as anything, but I think correct, clear and tail-recursive

def flag(m:List[Int], seen:List[Int]):List[Boolean] = {
m match {
case Nil => Nil
case x::xs => !seen.contains(x)::flag(xs, x::seen)
}
}

Jim

-----Original Message-----
From: Jan Kriesten [mailto:kriesten@mail.footprint.de]
Sent: Tuesday, March 10, 2009 1:17 PM
To: Windemuth Andreas
Cc: Scala list
Subject: Re: [scala] Flagging Uniques

Hi Andreas,

just playing around giving another solution:

def flagSeq[T]( s: Seq[T] ): List[Boolean] = {
def loop( e: T, s: Seq[T] ): List[Boolean] = (if( s.isEmpty )
List(true) else loop(s.first, s.drop(1)) + !s.contains(e))
val sRev = s.reverse
loop( sRev.first, sRev.drop(1) )
}

val seq: Seq[Int] = List(1,2,4,2,5,1,5)

val x = flagSeq( seq )

The difference is that I'm reversing the List first and look if the
element is contained in the tail. Though it's not yet tail-recursive...

Regards, --- Jan.

PLEASE READ: This message is for the named person's use only. It may contain confidential, proprietary or legally privileged information. No confidentiality or privilege is waived or lost by any mistransmission. If you receive this message in error, please delete it and all copies from your system, destroy any hard copies and notify the sender. You must not, directly or indirectly, use, disclose, distribute, print, or copy any part of this message if you are not the intended recipient. Nomura Holding America Inc., Nomura Securities International, Inc, and their respective subsidiaries each reserve the right to monitor all e-mail communications through its networks. Any views expressed in this message are those of the individual sender, except where the message states otherwise and the sender is authorized to state the views of such entity. Unless otherwise stated, any pricing information in this message is indicative only, is subject to change and does not constitute an offer to deal at any price quoted. Any reference to the terms of executed transactions should be treated as preliminary only and subject to our formal written confirmation.

Jesper Nordenberg
Joined: 2008-12-27,
User offline. Last seen 42 years 45 weeks ago.
Re: Flagging Uniques

Frohnhofer, James wrote:
> Slow as anything, but I think correct, clear and tail-recursive
>
> def flag(m:List[Int], seen:List[Int]):List[Boolean] = {
> m match {
> case Nil => Nil
> case x::xs => !seen.contains(x)::flag(xs, x::seen)
> }
> }

Unfortunately not tail recursive. You'll need to add a result parameter
for that:

def flag(m : List[Int], s : Set[Int], result : List[Boolean]) :
List[Boolean] =
m match {
case Nil => result
case x :: xs => flag(xs, s + x, !s.contains(x) :: result)
}

flag(seq, Set(), Nil).reverse

/Jesper Nordenberg

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: Flagging Uniques

On Tue, Mar 10, 2009 at 07:40:34PM +0100, Jesper Nordenberg wrote:
> Unfortunately not tail recursive. You'll need to add a result parameter
> for that:
>
> def flag(m : List[Int], s : Set[Int], result : List[Boolean]) :
> List[Boolean] =
> m match {
> case Nil => result
> case x :: xs => flag(xs, s + x, !s.contains(x) :: result)
> }

Indeed, and if you're not careful even this version won't be tail
recursive because it's neither final nor private, so if it were in a
class and not an object it would not be.

This all highlights the need for the @tailrec annotation which I have
working at home and warns when marked methods cannot be made tail
recursive, but in the meantime anyone who wants to be sure should look
at the bytecode. The version from by James finished like this:

107: invokestatic #70; //Method scala/runtime/BoxesRunTime.boxToBoolean:(Z)Ljava/lang/Boolean;
110: invokevirtual #74; //Method scala/List.$colon$colon:(Ljava/lang/Object;)Lscala/List;
113: areturn

Since :: was the last thing called in his version, it cannot be tail
recursive. Whereas jesper's last action was a call to flag, and so it
looks more like this:

105: invokevirtual #71; //Method scala/List.$colon$colon:(Ljava/lang/Object;)Lscala/List;
108: astore_3
109: astore_2
110: astore_1
111: goto 0

If you don't see a backward-branching goto, it's a bit unlikely it's
tail recursive.

Raoul Duke
Joined: 2009-01-05,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Flagging Uniques

> This all highlights the need for the @tailrec annotation

it always struck me as lame that many languages where TCO is
considered an important topic do not actively warn you about things
which can't be TCO'd. (i've heard that the O'Caml compiler can tell
you.)

Frohnhofer, James
Joined: 2009-03-10,
User offline. Last seen 42 years 45 weeks ago.
RE: Re: Flagging Uniques

Oh well. I tried.

Is it because '::' is actually the last function call and not 'flag'?

-----Original Message-----
From: news [mailto:news@ger.gmane.org] On Behalf Of Jesper Nordenberg
Sent: Tuesday, March 10, 2009 2:41 PM
To: scala@listes.epfl.ch
Subject: [scala] Re: Flagging Uniques

Frohnhofer, James wrote:
> Slow as anything, but I think correct, clear and tail-recursive
>
> def flag(m:List[Int], seen:List[Int]):List[Boolean] = {
> m match {
> case Nil => Nil
> case x::xs => !seen.contains(x)::flag(xs, x::seen)
> }
> }

Unfortunately not tail recursive. You'll need to add a result parameter
for that:

def flag(m : List[Int], s : Set[Int], result : List[Boolean]) :
List[Boolean] =
m match {
case Nil => result
case x :: xs => flag(xs, s + x, !s.contains(x) :: result)
}

flag(seq, Set(), Nil).reverse

/Jesper Nordenberg

PLEASE READ: This message is for the named person's use only. It may contain confidential, proprietary or legally privileged information. No confidentiality or privilege is waived or lost by any mistransmission. If you receive this message in error, please delete it and all copies from your system, destroy any hard copies and notify the sender. You must not, directly or indirectly, use, disclose, distribute, print, or copy any part of this message if you are not the intended recipient. Nomura Holding America Inc., Nomura Securities International, Inc, and their respective subsidiaries each reserve the right to monitor all e-mail communications through its networks. Any views expressed in this message are those of the individual sender, except where the message states otherwise and the sender is authorized to state the views of such entity. Unless otherwise stated, any pricing information in this message is indicative only, is subject to change and does not constitute an offer to deal at any price quoted. Any reference to the terms of executed transactions should be treated as preliminary only and subject to our formal written confirmation.

Randall R Schulz
Joined: 2008-12-16,
User offline. Last seen 1 year 29 weeks ago.
Re: Re: Flagging Uniques

On Tuesday March 10 2009, Raoul Duke wrote:
> > This all highlights the need for the @tailrec annotation

Offhand, that seems like a good idea.

> it always struck me as lame that many languages where TCO is
> considered an important topic do not actively warn you about things
> which can't be TCO'd. (i've heard that the O'Caml compiler can tell
> you.)

Clojure has a language-level construct that you must use if you want
tail-call optimization and it fails if not used at a properly
tail-recursive position. Clojure's originator (Rich Hickey) believes
that because his sole target execution platform, the JVM, does not
directly support tail-call optimization, he should not pretend to offer
it to the language's users with a silent fallback to an ordinary call.
Naturally, plain old recursive calls are OK, they just require new
stack frames for each one.

Randall Schulz

Justin du coeur
Joined: 2009-03-04,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Flagging Uniques
On Tue, Mar 10, 2009 at 2:52 PM, Paul Phillips <paulp@improving.org> wrote:
This all highlights the need for the @tailrec annotation

This strikes me as a *great* idea, for education as much as anything. 

The language has a lot of people like me, who are coming into it mainly from the OO side of things, who don't live and breathe functional style yet.  The tail-call thing is one of the subtler details -- I understand it intellectually pretty well, but I still have to work through each case carefully to figure out whether it actually manages to tail-recurse or not.  So having this annotation, to tell me when I mess it up, would be a huge benefit for really internalizing the technique...
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
@tailrec and @switch now in trunk

On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
> it always struck me as lame that many languages where TCO is
> considered an important topic do not actively warn you about things
> which can't be TCO'd.

On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
> Offhand, that seems like a good idea.

On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
> This strikes me as a *great* idea, for education as much as anything.

Who could resist such a groundswell of support?

$ scala
Welcome to Scala version 2.8.0.r0-b20090316104443

scala> import scala.annotation._
import scala.annotation._

// object is ok since method can't be overridden
scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
defined module o

// class with a method neither private nor final
scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
:7: error: could not optimize @tailrec annotated method
class c { @tailrec def foo(x: Int): Int = foo(x) }
^

scala> def isTrue(x: Char): Boolean = x < 'q'
isTrue: (Char)Boolean

// wrong way to get a switch
scala> def bar(c: Char) = (c: @switch) match {
| case 'a'|'b'|'c' => true
| case x if isTrue(x) => true
| case _ => false
| }
:8: error: could not emit switch for @switch annotated match
def bar(c: Char) = (c: @switch) match {
^

// right way to get a switch
scala> def bar(c: Char) = (c: @switch) match {
| case 'a'|'b'|'c' => true
| case x => isTrue(x)
| }
bar: (Char)Boolean

David Pollak
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: @tailrec and @switch now in trunk


On Mon, Mar 16, 2009 at 11:04 AM, Paul Phillips <paulp@improving.org> wrote:

On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
> it always struck me as lame that many languages where TCO is
> considered an important topic do not actively warn you about things
> which can't be TCO'd.

On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
> Offhand, that seems like a good idea.

On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
> This strikes me as a *great* idea, for education as much as anything.

Who could resist such a groundswell of support?

$ scala
Welcome to Scala version 2.8.0.r0-b20090316104443

scala> import scala.annotation._
import scala.annotation._

// object is ok since method can't be overridden
scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
defined module o


ooohhhh.... I've been wanting this!!  Thank you!
 


// class with a method neither private nor final
scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
<console>:7: error: could not optimize @tailrec annotated method
      class c { @tailrec def foo(x: Int): Int = foo(x) }
                             ^

scala>   def isTrue(x: Char): Boolean = x < 'q'
isTrue: (Char)Boolean

// wrong way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x if isTrue(x) => true
    |     case _              => false
    |   }
<console>:8: error: could not emit switch for @switch annotated match
        def bar(c: Char) = (c: @switch) match {
                                        ^

// right way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x              => isTrue(x)
    |   }
bar: (Char)Boolean

--
Paul Phillips      | We must respect the other fellow's religion, but only
Protagonist        | in the sense and to the extent that we respect his
Empiricist         | theory that his wife is beautiful and his children smart.
slap pi uphill!    |     -- H. L. Mencken



--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp
Joshua.Suereth
Joined: 2008-09-02,
User offline. Last seen 32 weeks 5 days ago.
Re: @tailrec and @switch now in trunk
You deserve a kitten!  @tailrec is *very* handy

On Mon, Mar 16, 2009 at 2:52 PM, David Pollak <feeder.of.the.bears@gmail.com> wrote:


On Mon, Mar 16, 2009 at 11:04 AM, Paul Phillips <paulp@improving.org> wrote:

On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
> it always struck me as lame that many languages where TCO is
> considered an important topic do not actively warn you about things
> which can't be TCO'd.

On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
> Offhand, that seems like a good idea.

On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
> This strikes me as a *great* idea, for education as much as anything.

Who could resist such a groundswell of support?

$ scala
Welcome to Scala version 2.8.0.r0-b20090316104443

scala> import scala.annotation._
import scala.annotation._

// object is ok since method can't be overridden
scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
defined module o


ooohhhh.... I've been wanting this!!  Thank you!
 


// class with a method neither private nor final
scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
<console>:7: error: could not optimize @tailrec annotated method
      class c { @tailrec def foo(x: Int): Int = foo(x) }
                             ^

scala>   def isTrue(x: Char): Boolean = x < 'q'
isTrue: (Char)Boolean

// wrong way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x if isTrue(x) => true
    |     case _              => false
    |   }
<console>:8: error: could not emit switch for @switch annotated match
        def bar(c: Char) = (c: @switch) match {
                                        ^

// right way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x              => isTrue(x)
    |   }
bar: (Char)Boolean

--
Paul Phillips      | We must respect the other fellow's religion, but only
Protagonist        | in the sense and to the extent that we respect his
Empiricist         | theory that his wife is beautiful and his children smart.
slap pi uphill!    |     -- H. L. Mencken



--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

J Robert Ray
Joined: 2008-12-18,
User offline. Last seen 3 years 16 weeks ago.
Re: @tailrec and @switch now in trunk

On Mon, Mar 16, 2009 at 11:04 AM, Paul Phillips wrote:
>
> scala>   def isTrue(x: Char): Boolean = x < 'q'
> isTrue: (Char)Boolean
>
> // wrong way to get a switch
> scala>   def bar(c: Char) = (c: @switch) match {
>     |     case 'a'|'b'|'c'    => true
>     |     case x if isTrue(x) => true
>     |     case _              => false
>     |   }
> :8: error: could not emit switch for @switch annotated match
>         def bar(c: Char) = (c: @switch) match {
>                                         ^

What is so bad about that form to make it worth adding the annotation?
I see an extra branch. Is there something bad about having
conditionals on the left side?

>
> // right way to get a switch
> scala>   def bar(c: Char) = (c: @switch) match {
>     |     case 'a'|'b'|'c'    => true
>     |     case x              => isTrue(x)
>     |   }
> bar: (Char)Boolean
>
> --
> Paul Phillips      | We must respect the other fellow's religion, but only
> Protagonist        | in the sense and to the extent that we respect his
> Empiricist         | theory that his wife is beautiful and his children smart.
> slap pi uphill!    |     -- H. L. Mencken
>

ijuma
Joined: 2008-08-20,
User offline. Last seen 22 weeks 2 days ago.
Re: @tailrec and @switch now in trunk

On Mon, 2009-03-16 at 13:10 -0700, J Robert Ray wrote:
> What is so bad about that form to make it worth adding the annotation?
> I see an extra branch. Is there something bad about having
> conditionals on the left side?

As the annotation says, you will not get a switch in the generated
bytecode. Instead you will get a chain of if/else statements. I would
guess that most people won't care about that particular annotation, but
it can be useful in some cases.

Best,
Ismael

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: @tailrec and @switch now in trunk

On Mon, Mar 16, 2009 at 01:10:12PM -0700, J Robert Ray wrote:
> What is so bad about that form to make it worth adding the annotation?
> I see an extra branch. Is there something bad about having
> conditionals on the left side?

One day I checked in some code and the compiler stopped compiling, and
it turned out the reason was that I had made a change like this: from

val x = 'D'

to

val x: Char = 'D'

You can read about this in more detail here:

https://lampsvn.epfl.ch/trac/scala/ticket/1456

The scalac scanner has a giant switch statement which has lines that
look like this, and in fact are written like this specifically so it
will compile into a switch:

case 'A' | 'B' | 'C' | 'D' | 'E' |
'F' | 'G' | 'H' | 'I' | 'J' |
'K' | 'L' | 'M' | 'N' | 'O' |
'P' | 'Q' | 'R' | 'S' | 'T' |
'U' | 'V' | 'W' | 'X' | 'Y' |
'Z' | '$' | '_' |
'a' | 'b' | 'c' | 'd' | 'e' |
'f' | 'g' | 'h' | 'i' | 'j' |
'k' | 'l' | 'm' | 'n' | 'o' |
'p' | 'q' | 'r' | 's' | 't' |
'u' | 'v' | 'w' | 'x' | 'y' |
'z' =>

Altering x from an undeclared Char to a declared Char caused the
compiler to no longer infer the singleton type, which caused the giant
match statement not to compile into a switch anymore, which caused the
stack depth to go into the hundreds where before it had stayed in the
10-20 range, which broked the compiler.

Since I wasted most of a day figuring out what had happened, I decided
that in the future it'd be better if we could assert our particularly
high level of interest in certain matches compiling down to switches.

John Nilsson
Joined: 2008-12-20,
User offline. Last seen 42 years 45 weeks ago.
Re: @tailrec and @switch now in trunk

On Mon, Mar 16, 2009 at 7:04 PM, Paul Phillips wrote:
> // class with a method neither private nor final
> scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
> :7: error: could not optimize @tailrec annotated method
>       class c { @tailrec def foo(x: Int): Int = foo(x) }
>                              ^

This looks handy indeed!

Would it be hard to add the text in you comment to the error message?

BR,
John

Andrés Testi
Joined: 2009-01-22,
User offline. Last seen 42 years 45 weeks ago.
Re: @tailrec and @switch now in trunk

Why @tailrec methods aren't final by default?

2009/3/16 Paul Phillips :
>
> On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
>> it always struck me as lame that many languages where TCO is
>> considered an important topic do not actively warn you about things
>> which can't be TCO'd.
>
> On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
>> Offhand, that seems like a good idea.
>
> On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
>> This strikes me as a *great* idea, for education as much as anything.
>
> Who could resist such a groundswell of support?
>
> $ scala
> Welcome to Scala version 2.8.0.r0-b20090316104443
>
> scala> import scala.annotation._
> import scala.annotation._
>
> // object is ok since method can't be overridden
> scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
> defined module o
>
> // class with a method neither private nor final
> scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
> :7: error: could not optimize @tailrec annotated method
>       class c { @tailrec def foo(x: Int): Int = foo(x) }
>                              ^
>
> scala>   def isTrue(x: Char): Boolean = x < 'q'
> isTrue: (Char)Boolean
>
> // wrong way to get a switch
> scala>   def bar(c: Char) = (c: @switch) match {
>     |     case 'a'|'b'|'c'    => true
>     |     case x if isTrue(x) => true
>     |     case _              => false
>     |   }
> :8: error: could not emit switch for @switch annotated match
>         def bar(c: Char) = (c: @switch) match {
>                                         ^
>
> // right way to get a switch
> scala>   def bar(c: Char) = (c: @switch) match {
>     |     case 'a'|'b'|'c'    => true
>     |     case x              => isTrue(x)
>     |   }
> bar: (Char)Boolean
>
> --
> Paul Phillips      | We must respect the other fellow's religion, but only
> Protagonist        | in the sense and to the extent that we respect his
> Empiricist         | theory that his wife is beautiful and his children smart.
> slap pi uphill!    |     -- H. L. Mencken
>

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: @tailrec and @switch now in trunk

On Mon, Mar 16, 2009 at 11:18:17PM -0300, Andrés Testi wrote:
> Why @tailrec methods aren't final by default?

Not sure if I'm understanding you correctly, but if you're suggesting
that the @tailrec annotation itself cause the method to be final, this
is a bad idea. The line between language constructs and annotation
influence may be a bit blurry in places, but not that blurry.

I could enhance the error messages to say exactly why it failed, but
it's not a priority because I suspect if you know enough to include the
annotation, you also know enough to figure out what happened.

loverdos
Joined: 2008-11-18,
User offline. Last seen 2 years 27 weeks ago.
Re: @tailrec and @switch now in trunk

paulp is probably going to inspire a new generation of geek-first-person-shooter-rpg games, where the main hero chases bugs, proposes new syntax/utilities and strategically thinks for the future. This will all happen in "ScalaLand", and most specifically in paulp's dominion, "Scalaca". A new epoch of avatars is raising... Are we witnessing the Reign of PaulP?
GREAT JOB Paul!!!!


Christos.
P.S. At the rate you invent things, I just hope will not not make the compiler lame at some point ;-)
On Mon, Mar 16, 2009 at 8:04 PM, Paul Phillips <paulp@improving.org> wrote:

On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
> it always struck me as lame that many languages where TCO is
> considered an important topic do not actively warn you about things
> which can't be TCO'd.

On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
> Offhand, that seems like a good idea.

On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
> This strikes me as a *great* idea, for education as much as anything.

Who could resist such a groundswell of support?

$ scala
Welcome to Scala version 2.8.0.r0-b20090316104443

scala> import scala.annotation._
import scala.annotation._

// object is ok since method can't be overridden
scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
defined module o

// class with a method neither private nor final
scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
<console>:7: error: could not optimize @tailrec annotated method
      class c { @tailrec def foo(x: Int): Int = foo(x) }
                             ^

scala>   def isTrue(x: Char): Boolean = x < 'q'
isTrue: (Char)Boolean

// wrong way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x if isTrue(x) => true
    |     case _              => false
    |   }
<console>:8: error: could not emit switch for @switch annotated match
        def bar(c: Char) = (c: @switch) match {
                                        ^

// right way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x              => isTrue(x)
    |   }
bar: (Char)Boolean

--
Paul Phillips      | We must respect the other fellow's religion, but only
Protagonist        | in the sense and to the extent that we respect his
Empiricist         | theory that his wife is beautiful and his children smart.
slap pi uphill!    |     -- H. L. Mencken



--
 __~O
-\ <,       Christos KK Loverdos
(*)/ (*)      http://ckkloverdos.com
marius
Joined: 2008-08-31,
User offline. Last seen 3 years 19 weeks ago.
Re: @tailrec and @switch now in trunk
Super cool !

On Mon, Mar 16, 2009 at 8:04 PM, Paul Phillips <paulp@improving.org> wrote:

On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
> it always struck me as lame that many languages where TCO is
> considered an important topic do not actively warn you about things
> which can't be TCO'd.

On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
> Offhand, that seems like a good idea.

On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
> This strikes me as a *great* idea, for education as much as anything.

Who could resist such a groundswell of support?

$ scala
Welcome to Scala version 2.8.0.r0-b20090316104443

scala> import scala.annotation._
import scala.annotation._

// object is ok since method can't be overridden
scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
defined module o

// class with a method neither private nor final
scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
<console>:7: error: could not optimize @tailrec annotated method
      class c { @tailrec def foo(x: Int): Int = foo(x) }
                             ^

scala>   def isTrue(x: Char): Boolean = x < 'q'
isTrue: (Char)Boolean

// wrong way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x if isTrue(x) => true
    |     case _              => false
    |   }
<console>:8: error: could not emit switch for @switch annotated match
        def bar(c: Char) = (c: @switch) match {
                                        ^

// right way to get a switch
scala>   def bar(c: Char) = (c: @switch) match {
    |     case 'a'|'b'|'c'    => true
    |     case x              => isTrue(x)
    |   }
bar: (Char)Boolean

--
Paul Phillips      | We must respect the other fellow's religion, but only
Protagonist        | in the sense and to the extent that we respect his
Empiricist         | theory that his wife is beautiful and his children smart.
slap pi uphill!    |     -- H. L. Mencken

Ricky Clarkson
Joined: 2008-12-19,
User offline. Last seen 3 years 2 weeks ago.
Re: @tailrec and @switch now in trunk

He also cleans code up, so I'd guess he won't make the compiler lame.

2009/3/17 Christos KK Loverdos :
>
> paulp is probably going to inspire a new generation of
> geek-first-person-shooter-rpg games, where the main hero chases bugs,
> proposes new syntax/utilities and strategically thinks for the future. This
> will all happen in "ScalaLand", and most specifically in paulp's dominion,
> "Scalaca". A new epoch of avatars is raising... Are we witnessing the Reign
> of PaulP?
> GREAT JOB Paul!!!!
>
>
> Christos.
> P.S. At the rate you invent things, I just hope will not not make the
> compiler lame at some point ;-)
> On Mon, Mar 16, 2009 at 8:04 PM, Paul Phillips wrote:
>>
>> On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
>> > it always struck me as lame that many languages where TCO is
>> > considered an important topic do not actively warn you about things
>> > which can't be TCO'd.
>>
>> On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
>> > Offhand, that seems like a good idea.
>>
>> On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
>> > This strikes me as a *great* idea, for education as much as anything.
>>
>> Who could resist such a groundswell of support?
>>
>> $ scala
>> Welcome to Scala version 2.8.0.r0-b20090316104443
>>
>> scala> import scala.annotation._
>> import scala.annotation._
>>
>> // object is ok since method can't be overridden
>> scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
>> defined module o
>>
>> // class with a method neither private nor final
>> scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
>> :7: error: could not optimize @tailrec annotated method
>>       class c { @tailrec def foo(x: Int): Int = foo(x) }
>>                              ^
>>
>> scala>   def isTrue(x: Char): Boolean = x < 'q'
>> isTrue: (Char)Boolean
>>
>> // wrong way to get a switch
>> scala>   def bar(c: Char) = (c: @switch) match {
>>     |     case 'a'|'b'|'c'    => true
>>     |     case x if isTrue(x) => true
>>     |     case _              => false
>>     |   }
>> :8: error: could not emit switch for @switch annotated match
>>         def bar(c: Char) = (c: @switch) match {
>>                                         ^
>>
>> // right way to get a switch
>> scala>   def bar(c: Char) = (c: @switch) match {
>>     |     case 'a'|'b'|'c'    => true
>>     |     case x              => isTrue(x)
>>     |   }
>> bar: (Char)Boolean
>>
>> --
>> Paul Phillips      | We must respect the other fellow's religion, but only
>> Protagonist        | in the sense and to the extent that we respect his
>> Empiricist         | theory that his wife is beautiful and his children
>> smart.
>> slap pi uphill!    |     -- H. L. Mencken
>
>
>
> --
>  __~O
> -\ <,       Christos KK Loverdos
> (*)/ (*)      http://ckkloverdos.com
>

loverdos
Joined: 2008-11-18,
User offline. Last seen 2 years 27 weeks ago.
Re: @tailrec and @switch now in trunk
Unless, overwhelmed by the cleaning frenziness, he sweeps the whole of scalac out. 

On Tue, Mar 17, 2009 at 10:32 AM, Ricky Clarkson <ricky.clarkson@gmail.com> wrote:
He also cleans code up, so I'd guess he won't make the compiler lame.

2009/3/17 Christos KK Loverdos <loverdos@gmail.com>:
>
> paulp is probably going to inspire a new generation of
> geek-first-person-shooter-rpg games, where the main hero chases bugs,
> proposes new syntax/utilities and strategically thinks for the future. This
> will all happen in "ScalaLand", and most specifically in paulp's dominion,
> "Scalaca". A new epoch of avatars is raising... Are we witnessing the Reign
> of PaulP?
> GREAT JOB Paul!!!!
>
>
> Christos.
> P.S. At the rate you invent things, I just hope will not not make the
> compiler lame at some point ;-)
> On Mon, Mar 16, 2009 at 8:04 PM, Paul Phillips <paulp@improving.org> wrote:
>>
>> On Tue, Mar 10, 2009 at 12:02:27PM -0700, Raoul Duke wrote:
>> > it always struck me as lame that many languages where TCO is
>> > considered an important topic do not actively warn you about things
>> > which can't be TCO'd.
>>
>> On Tue, Mar 10, 2009 at 12:17:01PM -0700, Randall R Schulz wrote:
>> > Offhand, that seems like a good idea.
>>
>> On Wed, Mar 11, 2009 at 12:47:45PM -0400, Justin du coeur wrote:
>> > This strikes me as a *great* idea, for education as much as anything.
>>
>> Who could resist such a groundswell of support?
>>
>> $ scala
>> Welcome to Scala version 2.8.0.r0-b20090316104443
>>
>> scala> import scala.annotation._
>> import scala.annotation._
>>
>> // object is ok since method can't be overridden
>> scala> object o { @tailrec def foo(x: Int): Int = foo(x) }
>> defined module o
>>
>> // class with a method neither private nor final
>> scala> class c { @tailrec def foo(x: Int): Int = foo(x) }
>> <console>:7: error: could not optimize @tailrec annotated method
>>       class c { @tailrec def foo(x: Int): Int = foo(x) }
>>                              ^
>>
>> scala>   def isTrue(x: Char): Boolean = x < 'q'
>> isTrue: (Char)Boolean
>>
>> // wrong way to get a switch
>> scala>   def bar(c: Char) = (c: @switch) match {
>>     |     case 'a'|'b'|'c'    => true
>>     |     case x if isTrue(x) => true
>>     |     case _              => false
>>     |   }
>> <console>:8: error: could not emit switch for @switch annotated match
>>         def bar(c: Char) = (c: @switch) match {
>>                                         ^
>>
>> // right way to get a switch
>> scala>   def bar(c: Char) = (c: @switch) match {
>>     |     case 'a'|'b'|'c'    => true
>>     |     case x              => isTrue(x)
>>     |   }
>> bar: (Char)Boolean
>>
>> --
>> Paul Phillips      | We must respect the other fellow's religion, but only
>> Protagonist        | in the sense and to the extent that we respect his
>> Empiricist         | theory that his wife is beautiful and his children
>> smart.
>> slap pi uphill!    |     -- H. L. Mencken
>
>
>
> --
>  __~O
> -\ <,       Christos KK Loverdos
> (*)/ (*)      http://ckkloverdos.com
>



--
 __~O
-\ <,       Christos KK Loverdos
(*)/ (*)      http://ckkloverdos.com

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