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

non-constants to @throws / @deprecated / ...

3 replies
rytz
Joined: 2008-07-01,
User offline. Last seen 45 weeks 5 days ago.
Hello,

there are some Scala annotations which expect a compile-time
constant argument, e.g. @deprecated, @migrate, @throws,
@SerialVersionUID.

This is not handled systematically right now. For instance,
the following will crash the JVM backend

class C {
  val c = classOf[Exception]
  @throws(c) def foo {}
}


We can
 1) silently ignore the annotation when there's a non-constant argument (like SerialVersionUID)
 2) warn or fail late (in the backend)
 3) special-case typedAnnotation to check arguments to these known annotations early
 4) introduce some mechanism to require a constant argument, e.g.
     class throws(@annotation.meta.constant clazz: Class[_]) extends StaticAnnotation


Let me know your opinions.

Lukas

odersky
Joined: 2008-07-29,
User offline. Last seen 45 weeks 6 days ago.
Re: non-constants to @throws / @deprecated / ...


On Wed, Mar 31, 2010 at 3:46 PM, Lukas Rytz <lukas.rytz@epfl.ch> wrote:
Hello,

there are some Scala annotations which expect a compile-time
constant argument, e.g. @deprecated, @migrate, @throws,
@SerialVersionUID.

This is not handled systematically right now. For instance,
the following will crash the JVM backend

class C {
  val c = classOf[Exception]
  @throws(c) def foo {}
}


We can
 1) silently ignore the annotation when there's a non-constant argument (like SerialVersionUID)
 2) warn or fail late (in the backend)
 3) special-case typedAnnotation to check arguments to these known annotations early
 4) introduce some mechanism to require a constant argument, e.g.
     class throws(@annotation.meta.constant clazz: Class[_]) extends StaticAnnotation

definitely 4) -- Martin
 
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: non-constants to @throws / @deprecated / ...

On Wed, Mar 31, 2010 at 03:46:24PM +0200, Lukas Rytz wrote:
> there are some Scala annotations which expect a compile-time constant
> argument, e.g. @deprecated, @migrate, @throws, @SerialVersionUID.

Thank you, I've been meaning to bring this up forever. (Although I'm
ostensibly reworking @elidable as per martin's idea, it also is in this
category, and my struggle with this issue is documented therein.)

> 4) introduce some mechanism to require a constant argument, e.g.
> class throws(@annotation.meta.constant clazz: Class[_]) extends
> StaticAnnotation

I am pretty sure that more expressions could be treated as constants for
this purpose than presently are, and it winds up making a big difference
in usability. (This is going to be from memory so forgive any
inaccuracies.) If an annotation requires a constant Int argument then
you have to know about the secret sauce for the constant folder:

object Foo {
val Bar1: Int = 1 // does not work, not singleton type
val Bar2 = 1 // does not work, not marked final
final val Bar3 = 1 // does work
final val Bar4: Int = 1 // can't remember if this works
}

The real killer is the difficulty of applying any abstraction. For
instance there are a couple dozen places with migration annotations with
very tiny variations on this message:

"As of 2.8, this operation creates a new map. To add the elements as a\n"+
"side effect to an existing map and return that map itself, use ++=."

The message is just duplicated across all of those. To my last breath I
will fight such duplication. It's almost worse in documentation than in
code because there are no little static checking tricks to pull -- once
the comments start drifting apart, only an insanely tedious and utterly
thankless effort from some future party will make them consistent with
whatever future reality is. Which of course never happens. It's like
using a time machine to send incorrect documentation to the future.

So if there were some way to write a function which I could annotate as
being guaranteed to do a straight manipulation of constant expressions,
if I could write

def mymsg(s: String) = "blah blah this " + s + " blah blah"

and if the compiler would inline the string addition and constant fold
it for the purposes of annotation, then the world looks pretty again.
Do we think this is unduly difficult and/or solving the wrong problem?
I'll endorse any solution which lets me eliminate the duplication.

Incidentally, another variation on massive-cut-and-paste is that every
annotation in scala.annotation.target has the same or almost the same 40
line doc comment. But maybe the new scaladoc makes it possible to
tackle that one that way?

odersky
Joined: 2008-07-29,
User offline. Last seen 45 weeks 6 days ago.
Re: non-constants to @throws / @deprecated / ...


On Wed, Mar 31, 2010 at 6:23 PM, Paul Phillips <paulp@improving.org> wrote:
On Wed, Mar 31, 2010 at 03:46:24PM +0200, Lukas Rytz wrote:
> there are some Scala annotations which expect a compile-time constant
> argument, e.g. @deprecated, @migrate, @throws, @SerialVersionUID.

Thank you, I've been meaning to bring this up forever.  (Although I'm
ostensibly reworking @elidable as per martin's idea, it also is in this
category, and my struggle with this issue is documented therein.)

>  4) introduce some mechanism to require a constant argument, e.g.
>      class throws(@annotation.meta.constant clazz: Class[_]) extends
> StaticAnnotation

I am pretty sure that more expressions could be treated as constants for
this purpose than presently are, and it winds up making a big difference
in usability.  (This is going to be from memory so forgive any
inaccuracies.) If an annotation requires a constant Int argument then
you have to know about the secret sauce for the constant folder:

object Foo {
 val Bar1: Int = 1  // does not work, not singleton type
 val Bar2 = 1       // does not work, not marked final
 final val Bar3 = 1 // does work
 final val Bar4: Int = 1 // can't remember if this works
}

The real killer is the difficulty of applying any abstraction.  For
instance there are a couple dozen places with migration annotations with
very tiny variations on this message:

   "As of 2.8, this operation creates a new map.  To add the elements as a\n"+
   "side effect to an existing map and return that map itself, use ++=."

The message is just duplicated across all of those.  To my last breath I
will fight such duplication.  It's almost worse in documentation than in
code because there are no little static checking tricks to pull -- once
the comments start drifting apart, only an insanely tedious and utterly
thankless effort from some future party will make them consistent with
whatever future reality is.  Which of course never happens.  It's like
using a time machine to send incorrect documentation to the future.

So if there were some way to write a function which I could annotate as
being guaranteed to do a straight manipulation of constant expressions,
if I could write

 def mymsg(s: String) = "blah blah this " + s + " blah blah"

and if the compiler would inline the string addition and constant fold
it for the purposes of annotation, then the world looks pretty again.
Do we think this is unduly difficult and/or solving the wrong problem?
I'll endorse any solution which lets me eliminate the duplication.

That's a fairly tall order. Doing arbitrary compile-time computations is a pretty  big change to spec and (probably less so) to implement.
Maybe, just maybe use @inline. But there are all sorts of unknowns regarding separate compilation, termination, and so on. So this looks like a big project where someone would have to think things through in detail and then male a SID proposal.

Incidentally, another variation on massive-cut-and-paste is that every
annotation in scala.annotation.target has the same or almost the same 40
line doc comment.  But maybe the new scaladoc makes it possible to
tackle that one that way?

Yes, this one is easy. Just define and use a variable.

 Cheers

 -- Martin

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