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

assert's second argument not by-name

2 replies
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.

I was very surprised to find out when looking into https://lampsvn.epfl.ch/trac/scala/ticket/834 that Predef.assert's
(and friends') second argument is not by-name.

def assert(assertion: Boolean, message: Any)
def assume(assumption: Boolean, message: Any)
def require(requirement: Boolean, message: Any)

I changed all three of these to message: => Any and ran "ant dist" from scratch with and without it. After three runs
the by-name version was consistently almost 2% faster (24 minutes vs. 23:30.) This is because there are many asserts in
the compiler which do expensive string operations to generate error messages, but which are under normal circumstances
never used.

Is there any reason these shouldn't be made by name right now? Is there an overall logic to why their first arguments
aren't by-name either? Given that assert is the canonical example for the use of by-name arguments, and in fact is the
example in "Programming in Scala", I'm guessing there's some reasoning regarding the first argument, but I think it's
the second one imposing most of the performance penalty anyway.

Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: assert's second argument not by-name

I think it was mainly because we thought it would too slow. The
optimizer is already capable of inlining such asserts, but it slows
compilation quite a bit. The idea was to have a 'light' optimizer on
by default, that would inline only calls in Predef, but which I never
got the time to implement.

If numbers show it actually gets faster, I'm in favor of switching to
the by-name versions.

Iulian

On Feb 10, 2009, at 6:07 PM, Paul Phillips wrote:

> I was very surprised to find out when looking into https://lampsvn.epfl.ch/trac/scala/ticket/834
> that Predef.assert's
> (and friends') second argument is not by-name.
>
> def assert(assertion: Boolean, message: Any)
> def assume(assumption: Boolean, message: Any)
> def require(requirement: Boolean, message: Any)
>
> I changed all three of these to message: => Any and ran "ant dist"
> from scratch with and without it. After three runs
> the by-name version was consistently almost 2% faster (24 minutes
> vs. 23:30.) This is because there are many asserts in
> the compiler which do expensive string operations to generate error
> messages, but which are under normal circumstances
> never used.
>
> Is there any reason these shouldn't be made by name right now? Is
> there an overall logic to why their first arguments
> aren't by-name either? Given that assert is the canonical example
> for the use of by-name arguments, and in fact is the
> example in "Programming in Scala", I'm guessing there's some
> reasoning regarding the first argument, but I think it's
> the second one imposing most of the performance penalty anyway.
>

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: assert's second argument not by-name

On Tue, Feb 10, 2009 at 11:41:55PM +0100, Iulian Dragos wrote:
> I think it was mainly because we thought it would too slow. The optimizer
> is already capable of inlining such asserts, but it slows compilation
> quite a bit. The idea was to have a 'light' optimizer on by default, that
> would inline only calls in Predef, but which I never got the time to
> implement.
>
> If numbers show it actually gets faster, I'm in favor of switching to the
> by-name versions.

In addition to my earlier numbers which looked pretty convincing to me that it's faster by name, here are some other
numbers that might be relevant to the decision.

Trunk:
8429 classfiles
-rw-r--r-- 1 paulp staff 6432039 Feb 10 11:24 scala-compiler.jar
-rw-r--r-- 1 paulp staff 4485479 Feb 10 11:24 scala-library.jar

Trunk with -optimise:
8204 classfiles
-rw-r--r-- 1 paulp admin 6557470 Feb 10 12:53 scala-compiler.jar
-rw-r--r-- 1 paulp admin 4406499 Feb 10 12:53 scala-library.jar

With by-name assert:
8644 classfiles
-rw-r--r-- 1 paulp staff 6630193 Feb 10 11:21 scala-compiler.jar
-rw-r--r-- 1 paulp staff 4496903 Feb 10 11:21 scala-library.jar

With by-name assert and -optimise:
8423 classfiles
-rw-r--r-- 1 paulp admin 6599852 Feb 10 12:00 scala-compiler.jar
-rw-r--r-- 1 paulp admin 4406742 Feb 10 12:00 scala-library.jar

The optimal performance would probably lie with using by-name selectively, but personally I wouldn't be enthusiastic
about sending the message that you need by-name and eager versions of methods just for performance. Much better to see
if we can get inlining working.

To get -optimise builds I had to insert the option just on the quick targets (see
https://lampsvn.epfl.ch/trac/scala/ticket/1710 for details.) It seems like -optimise is not too far from being reliable,
but that last little distance (if it is in fact a little distance) is still enough to disincentivize its use. I have
come a long ways in understanding the compiler internals and hopefully I can assist before much longer.

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