@throws annotation/ScalaDoc

833 views
Skip to first unread message

Simon Ochsenreither

unread,
Sep 15, 2012, 6:22:59 AM9/15/12
to scala-i...@googlegroups.com
Hi everyone,

Bruce Eckel brought up the issue that most APIs lack a description of possible exceptions¹.

While looking into it, I realized that the current way to do it is very boilerplatey:

/** This method does ...
  * @throws IllegalArgumentException if `a` is less than 0. */
@throws(classOf[IllegalArgumentException])
def foo(a: Int) = ...

Without great IDE ScalaDoc support (which is not there), this stuff can very easily become out of sync or outdated.
As the guy implementing the @throws ScalaDoc tag in the first place, I guess it is my task to clean that up...

in the best tradition of "let's add a second parameter to @migration/@deprecated/...", I propose something like this instead:

@throws(classOf[IllegalArgumentException], "if `a` is less than 0.")
def foo(a: Int) = ...

Normally, I would be reluctant to add some documentation-specific value to an annotation, but I think we could gain some additional benefit from it in later versions.
Imagine some compiler-mode (or macro )which will warn if a method will very likely throw an error for the given arguments!

Normally, this would be a Turing-complete task, but an useful subset could be verified by embedding code snippets into the @throws annotation like this:

@throws(classOf[IllegalArgumentException], "`if (a < 0)`")
def foo(a: Int) = ...

This way we would benefit from less boilerplatey documentation and be able to use the information during compilation if we want to do that in future versions!
This is of course purely hypothetical, but after sleeping a night over it, I think I'm in favor of adding a second parameter to the @throws annotation and deprecating the ScalaDoc @throws tag.

What do you think?

Thanks and bye,

Simon

¹ https://groups.google.com/forum/?hl=en_US#!topic/scala-user/3vfNJdGtyxw

Simon Ochsenreither

unread,
Sep 15, 2012, 11:43:20 AM9/15/12
to scala-i...@googlegroups.com
By the way, why are we using @throws(classOf[FooException]) instead of @throws[FooException]?

Is there any reason to force people through the classOf incantations, if we never actually need an instance?

I would like to suggest the following implementation:

class throws[T <: Throwable](cause: String) extends scala.annotation.StaticAnnotation {
  def this(clazz: Class[T]) = this("")
}

It improves on the code before:
  • more concise and readable
  • source compatible (didn't check it yet)
  • actually enforces that we are throwing a Throwable, and not a String

What do you think?

Thanks and bye!

Simon

(I wouldn't mark the old way deprecated yet, because it's a bit short on notice for 2.10 (and I really would prefer to have the same API going forward when the let's-add-@throws-annotations-everywhere work hits GitHub...)

Thorpe, Michael

unread,
Sep 15, 2012, 11:48:26 AM9/15/12
to <scala-internals@googlegroups.com>, scala-i...@googlegroups.com
Sounds like you're trying to make a Sage-like system really (http://sage.soe.ucsc.edu/sage-tr.pdf)

Sounds pretty awesome + useful.

Paul Phillips

unread,
Sep 15, 2012, 12:48:18 PM9/15/12
to scala-i...@googlegroups.com
On Sat, Sep 15, 2012 at 8:43 AM, Simon Ochsenreither <simon.och...@gmail.com> wrote:

Is there any reason to force people through the classOf incantations, if we never actually need an instance?

Not that I can think of.  Sounds great to me if you can make it work.

Simon Ochsenreither

unread,
Sep 15, 2012, 12:53:04 PM9/15/12
to scala-i...@googlegroups.com
Hi Paul,


Not that I can think of.  Sounds great to me if you can make it work.

I'm already on it. I'm just wondering if I can build it in one step or if I need to bootstrap a new compiler. What does your crystal ball say? :-)
(Affected code would probably be in GenJVM/GenASM, ClassfileParser and the ScalaDoc stuff...)

Thanks,

Simon

Paul Phillips

unread,
Sep 15, 2012, 1:00:06 PM9/15/12
to scala-i...@googlegroups.com
On Sat, Sep 15, 2012 at 9:53 AM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
I'm already on it. I'm just wondering if I can build it in one step or if I need to bootstrap a new compiler. What does your crystal ball say? :-)
(Affected code would probably be in GenJVM/GenASM, ClassfileParser and the ScalaDoc stuff...)

I won't make confident predictions when it comes to annotations, but as you described it I don't think it will require anything beyond a normal recompile.

Simon Ochsenreither

unread,
Sep 16, 2012, 10:25:34 AM9/16/12
to scala-i...@googlegroups.com
Almost done, btw. Just have one case left were I get the type variable instead of the actually instantiated type back during serialization. This should be trivial to solve, but it takes a bit of time currently, because running the tests alone takes more than 2:15 hours at my laptop (don't even think about Ctrl+S in Eclipse ... "compile on save" will completely kill the machine.

It looks like a nice, compatible improvement. The only issue seems to be whether adding the cause to the annotation is the "right thing" to do, because annotations are not inherited, but ScalaDoc is. But on the other side, without inheritable annotations we need to add @throws to every inheriting method either way.

I'm slightly in favor of going the annotation-only way, because it can prevent cases where the ScalaDoc uses @throws tags, but no actual @throws annotation exists...

What do you think?

Simon
Reply all
Reply to author
Forward
0 new messages