Strange behavior when combing implicit conversion with () => Unit input parameter

68 views
Skip to first unread message

Yoav Abrahami

unread,
Jul 22, 2011, 12:23:46 PM7/22/11
to scala-language
Hi Scala gurus,

I've started using Scala quite recently, and came upon what seems like
a strange and inconsistent behavior of the scala compiler.
As I work quite a bit with Threads, I create Runnable implementations
(the reason I am using ThreadPoolExecutor and not Actors is out of
scope for this issue).

I hope someone here can shade some light and explain what's going on
here and why it seems (to me) like an inconsistent handling of the
scala compiler.

In order to write the most elegant code I can with Runnable, I've
played with implicit and explicit conversions from a code block to a
Runnable. What I've found can be summarized as (see the code below)

()=>Unit implicitly converted to Runnable - does not work as expected
- prints hello 1 once
()=>Unit explicitly converted to Runnable - does work as expected -
prints hello 1 twice
(String)=>Unit implicitly converted to RunnableString - does work as
expected - prints hello 1 twice
(String)=>Unit explicitly converted to RunnableString - does work as
expected - prints hello 1 twice

Cheers,
Yoav

The code -
I've tried to introduce the following implicit conversion.

implicit def funcToRunnable(x: => Unit): Runnable = new Runnable {
println("converting...")
def run = {
x
}
}

Then to use it the following way

def playRunnableImplicit() {
println("playRunnableImplicit")
playRunnable({
println("hello 1")
println("hello 2")
})
}

where the method playRunnable (a method written to make the issue here
explicit) is

def playRunnable(r: Runnable): Unit = {
println("playRunnable.playing runnable")
r.run()
println("playRunnable.playing the runnable a second time")
r.run()
println("playRunnable.played runnable")
}

when running the playRunnableImplicit, the printed output is not what
I'd expect
playRunnableImplicit
hello 1
converting...
playRunnable.playing runnable
hello 2
playRunnable.playing the runnable a second time
hello 2
playRunnable.played runnable

The problem is that the first statement of the code block given to the
conversion is executed before the implicit conversion is done.

When using explicit conversion, we get the following

def playRunnableExplicit() {
println("playRunnableExplicit")
playRunnable(funcToRunnable({
println("hello 1")
println("hello 2")
}))
}

playRunnableExplicit
converting...
playRunnable.playing runnable
hello 1
hello 2
playRunnable.playing the runnable a second time
hello 1
hello 2
playRunnable.played runnable

interesting that by just adding the explicit conversion instead of the
implicit conversion, we get a different result.

Also, If we use the same pattern for an implicit conversion from
anything other then ()=>Unit block, it all works as expected. For
instance, if we define a trait RunnableString and a conversion from
(String)=>Unit, such as below, everything works as expected


trait RunnableString {
def run(s: String)
}

implicit def funcToRunnableString(x: String => Unit): RunnableString
= new RunnableString {
println("converting...")
def run(s: String) = {
x(s)
}
}

def playRunnableString(r: RunnableString): Unit = {
println("playRunnable.playing runnable")
r.run("a")
println("playRunnable.playing the runnable a second time")
r.run("b")
println("playRunnable.played runnable")
}

def playRunnableStringImplicit() {
println("playRunnableStringImplicit")
playRunnableString({s: String =>
println("hello 1 " + s)
println("hello 2 " + s)
})
}

def playRunnableStringExplicit() {
println("playRunnableStringExplicit")
playRunnableString(funcToRunnableString({s: String =>
println("hello 1 " + s)
println("hello 2 " + s)
}))
}

and the output is then
playRunnableStringImplicit
converting...
playRunnable.playing runnable
hello 1 a
hello 2 a
playRunnable.playing the runnable a second time
hello 1 b
hello 2 b
playRunnable.played runnable

playRunnableStringExplicit
converting...
playRunnable.playing runnable
hello 1 a
hello 2 a
playRunnable.playing the runnable a second time
hello 1 b
hello 2 b
playRunnable.played runnable

Iain McGinniss

unread,
Jul 22, 2011, 2:05:54 PM7/22/11
to scala-l...@googlegroups.com
I think what you might be bumping up against here is that blocks are not actually functions:


I think what you needed to do was:

def playRunnableImplicit() {
   println("playRunnableImplicit")
   playRunnable(() => {

     println("hello 1")
     println("hello 2")
   })
 }

It seems there are some funny rules which I don't claim to fully understand influencing your examples, but perhaps the above links can help clarify things (or someone else can jump in and describe much more eloquently what's happening).

Iain

Daniel Sobral

unread,
Jul 22, 2011, 3:20:56 PM7/22/11
to scala-l...@googlegroups.com
On Fri, Jul 22, 2011 at 13:23, Yoav Abrahami <yoa...@gmail.com> wrote:
> Hi Scala gurus,
>
> In order to write the most elegant code I can with Runnable, I've
> played with implicit and explicit conversions from a code block to a
> Runnable. What I've found can be summarized as (see the code below)

Code block is not an object. There's no "thunk" in Scala -- you either
have a function, or you don't. A code of block is simply a syntactical
scope whose value is that of the last statement. So you can't
"convert" a code block into something.

>
> ()=>Unit implicitly converted to Runnable - does not work as expected
> - prints hello 1 once

"() => Unit" is a function with one parameter list of arity 0. A
Function0, in other words.

>  implicit def funcToRunnable(x: => Unit): Runnable = new Runnable {

A "=> Unit" is not a function at all. "=> Unit" is the same thing as
"Unit", but the parameter is passed by name instead of by value. In
practice, it means whatever is passed in place of the parameter is not
first evaluated and then have its value passed but, instead, is passed
"as is", and evaluated it time it is used.

Anyway, "=> Unit" is different than "() => Unit".

>    println("converting...")
>    def run = {
>      x
>    }
>  }
>

>  def playRunnableImplicit() {
>    println("playRunnableImplicit")
>    playRunnable({
>      println("hello 1")
>      println("hello 2")
>    })

So, the parameter is { println("hello 1"); println("hello 2") }, which
does not conform to Runnable. However, there's a conversion from Unit
to Runnable, and the type of that parameter is Unit. The value of a
block is the value of it's last statement, but since Unit is being
passed by name, println("hello 2") is passed instead of just ()
(return value of println, not to be confused with empty parameter
list).

>  }

At any rate, even if what you want were doable, it wouldn't be a good
idea. That's a gratuitous implicit conversion, saving a single token.
If, instead, you named funcToRunnable just "runnable", you could then
write

playRunnable(runnable { print("hello 1"); print("hello 2") })

No implicits required, and very little syntactic overhead.

--
Daniel C. Sobral

I travel to the future all the time.

Yoav Abrahami

unread,
Jul 23, 2011, 6:42:18 AM7/23/11
to scala-language
Iain,

thanks for your answer.
I have tried writing things like
   playRunnable(() => {
   playRunnable( => {
   playRunnable({ () =>
   playRunnable({ =>

but non of them compile.
I still did not find how to make scala consider a "code block" as a
()=>Unit func.

On Jul 22, 9:05 pm, Iain McGinniss <iainmc...@gmail.com> wrote:
> I think what you might be bumping up against here is that blocks are not
> actually functions:
>
> http://daily-scala.blogspot.com/2010/05/return-value-of-block.htmlhttp://downgra.de/2010/08/05/scala_gotcha_blocks_and_functions/

Yoav Abrahami

unread,
Jul 23, 2011, 6:46:43 AM7/23/11
to scala-language
Daniel,
What I fail to understand is why I cannot create a function / method
that does not get any parameters.
The case with RunnableString clearly works as scala considers the
block
{ s: String =>
println("hello 1 " + s)
println("hello 2 " + s)
}
as a function, while it does not consider the block
{
println("hello 1")
println("hello 2")
}
as a function

is there a syntactic way to express in scala something that does not
get input parameters but such that can be evaluated later?

Thanks,
Yoav

√iktor Ҡlang

unread,
Jul 23, 2011, 9:21:54 AM7/23/11
to scala-l...@googlegroups.com

def block2fun0[T](block: => T): () => T = () => block

Yoav Abrahami

unread,
Jul 23, 2011, 11:06:47 AM7/23/11
to scala-language
hi Viktor and Daniel,
Thanks for your answer.
Viktor, the block2fun0 creates a () => T func. I am wondering about
creating a () => Unit, which is a bit different.

Let me try to clarify my question -
Consider the following code block
{println("hello 1"); println("hello 2") }

now consider using the following to convert it to a runnable
implicit def funcToRunnable(x: => Unit): Runnable = new Runnable
{ def run = { x } }

I fail to understand why Scala considers g(funcToRunnable(block)) as
one thing and g(block) (with implicit conversion) as something
else...
aren't the rules for implicit conversion are that it should do the
same thing as if we were using explicit conversion?

It seems that the Scala compiler does the following
in the case of explicit conversion - considers all the code block as a
() => Unit and passes all the block to the funcToRunnable method.
in the case of implicit conversion - executes the code block, taking
only the last statement and passes it to the funcToRunnable method.
strange, it's it?

Daniel Sobral

unread,
Jul 23, 2011, 11:36:18 AM7/23/11
to scala-l...@googlegroups.com
On Sat, Jul 23, 2011 at 07:46, Yoav Abrahami <yoa...@gmail.com> wrote:
> Daniel,
> What I fail to understand is why I cannot create a function / method
> that does not get any parameters.

Functions and methods are different things. Do not confuse them.
Functions must ALWAYS get at list a 0-arity parameter list, because
that's how they "apply" syntactic sugar gets invoked.

> The case with RunnableString clearly works as scala considers the
> block
> { s: String =>
> println("hello 1 " + s)
> println("hello 2 " + s)
> }

> as a function, while it does not consider the block
> {
> println("hello 1")
> println("hello 2")
> }
> as a function

Because it has no parameter list. This would be a function:

{
() =>


println("hello 1")
println("hello 2")
}

>

Daniel Sobral

unread,
Jul 23, 2011, 11:36:51 AM7/23/11
to scala-l...@googlegroups.com
On Sat, Jul 23, 2011 at 12:36, Daniel Sobral <dcso...@gmail.com> wrote:
> On Sat, Jul 23, 2011 at 07:46, Yoav Abrahami <yoa...@gmail.com> wrote:
>> Daniel,
>> What I fail to understand is why I cannot create a function / method
>> that does not get any parameters.
>
> Functions and methods are different things. Do not confuse them.
> Functions must ALWAYS get at list a 0-arity parameter list, because

I meant "at _least_ a 0-arity parameter least" here.

Daniel Sobral

unread,
Jul 23, 2011, 11:38:27 AM7/23/11
to scala-l...@googlegroups.com
2011/7/23 √iktor Ҡlang <viktor...@gmail.com>:

> def block2fun0[T](block: => T): () => T = () => block

This is pretty much what he had, but he is trying to make it apply
implicitly, which causes problem as I described. Specifically:

scala> implicit def block2fun0[T](block: => T): () => T = () => block
block2fun0: [T](block: => T)() => T

scala> val f: () => Unit = {


| println("hello 1")
| println("hello 2")
| }

hello 1
f: () => Unit = <function0>

scala> f()
hello 2

Daniel Sobral

unread,
Jul 23, 2011, 11:46:16 AM7/23/11
to scala-l...@googlegroups.com
On Sat, Jul 23, 2011 at 12:06, Yoav Abrahami <yoa...@gmail.com> wrote:
> hi Viktor and Daniel,
> Thanks for your answer.
> Viktor, the block2fun0 creates a () => T func. I am wondering about
> creating a () => Unit, which is a bit different.
>
> Let me try to clarify my question -
> Consider the following code block
>   {println("hello 1");  println("hello 2") }
>
> now consider using the following to convert it to a runnable
>   implicit def funcToRunnable(x: => Unit): Runnable = new Runnable
> { def run = { x } }
>
> I fail to understand why Scala considers g(funcToRunnable(block)) as
> one thing and g(block) (with implicit conversion) as something
> else...
> aren't the rules for implicit conversion are that it should do the
> same thing as if we were using explicit conversion?
>
> It seems that the Scala compiler does the following
> in the case of explicit conversion - considers all the code block as a
> () => Unit and passes all the block to the funcToRunnable method.
> in the case of implicit conversion - executes the code block, taking
> only the last statement and passes it to the funcToRunnable method.
> strange, it's it?

You will *not* understand as long as you persist in thinking of "code
block". While there's something in Scala code block, it is not what
you think it is. So, first, make it clear to yourself: THERE IS NO
SUCH THING AS A CODE BLOCK. Convince yourself of that. If you start
reading the code and think "code block", stop and say that again:
there is no such thing as a code block. Once you take that completely
out of your mind, you can go back to the code:

{ s: String =>
println("hello 1 " + s)
println("hello 2 " + s)
}

This is a function literal. Function literals are either simple
expressions or delimited by () or {}, and they either have "_" in them
as placeholder parameters, or they start with "parameters =>", where
"parameters" may be a single identifier, with or without type, or a
list of identifiers inside parenthesis. Again, this is a function --
learn to recognize what marks a function.

{


println("hello 1")
println("hello 2")
}

This is nothing. It is just a couple of statements inside a scope delimiter.

After you have that fully understood, then you can start thinking of
"code block" as a delimited list of declarations and statements with a
value.

√iktor Ҡlang

unread,
Jul 23, 2011, 12:39:35 PM7/23/11
to scala-l...@googlegroups.com
So the conclusion here is:

you can have an implicit conversion between () => T and Runnable, but you'll need to use it like this:

val r: Runnable = () => println("pigdog")

which makes it a bit easier to just have a method called "runnable" that takes a by-name parameter of type T and returns a Runnable that invokes that by-name parameter:

val r = runnable { println("pigdog" }

Now, if there really is not a convincing reason to work with runnables in user code at all, I'd recommend working with () => T instead, it's way more useful.

val r  = () => println("pigdog")
--
Viktor Klang

Akka Tech Lead
Typesafe - Enterprise-Grade Scala from the Experts

Twitter: @viktorklang

Stephen Haberman

unread,
Jul 23, 2011, 4:44:25 PM7/23/11
to scala-l...@googlegroups.com

{
println("hello 1")
println("hello 2")
}

This is nothing. It is just a couple of statements inside a scope delimiter.

Okay, then how to do you explain:


AFAICT, the "couple of statements inside a scope delimiter" can indeed be a function, as the call to doFunction shows.

It's quite odd that the same syntax (doFunction { ... } vs. doSam { ... }) results in very different behavior depending on whether an implicit conversion is involved.

- Stephen

Roland Kuhn

unread,
Jul 23, 2011, 5:39:27 PM7/23/11
to scala-l...@googlegroups.com
Well, put yourself in the position of the compiler: in the first case, you know to expect a function, and the spec says that if the argument types are fully known then a special syntax for function literals is allowed (which you use). This special case is extremely useful for writing library functions which act as if they were keywords (i.e. synchronized {} and friends). In the second case, a SAM is needed, for which a block is given, hence the return value of that block is inspected if it would fit the bill, triggering implicit conversion if needed and available.

So, in essence you are thrown off by the special case for FunctionN & PartialFunction, or more appropriately, that this special case is not applied when taking into account implicit conversions. Again, put yourself in the position of the compiler: you would have to unwind potentially a lot of stuff to re-check the whole code block when passed into the conversion method.

Regards,

Roland

Daniel Sobral

unread,
Jul 24, 2011, 7:09:34 PM7/24/11
to scala-l...@googlegroups.com
On Sat, Jul 23, 2011 at 17:44, Stephen Haberman
<stephen....@gmail.com> wrote:
>> {
>> println("hello 1")
>> println("hello 2")
>> }
>>
>> This is nothing. It is just a couple of statements inside a scope
>> delimiter.
>
> Okay, then how to do you explain:
> https://gist.github.com/1101709

I have explained it in two different ways already, but I'll try again.
Remember, first, that "=> Unit" is *not* a function. It is a parameter
passed by-name -- go look on wikipedia about that.

So, the first thing to notice is that there is no function anywhere,
and "doFunction" is incorrectly named. So, since this code has no
function in it, we can move ahead and understand how it works. If you
can't let go of the fact it has no function, then go back, re-read the
spec, re-read stuff I wrote... hell, read stack overflow about it.
There's no function signature anywhere, therefore there is no
function.

NEXT, let's see how it works:

def doFunction(f: => Unit) = { println("got " + (f _)) ; f ; f }
doFunction { println("1"); println("2") }

The grossly misnamed "doFunction" method takes a by-name Unit
parameter "f". That means that everywhere "f" appears, it is replaced
with what was passed. That means it will do this:

{ println("got " + ({ println("1"); println("2") } _)) ; {
println("1"); println("2") } ; { println("1"); println("2") } }

You might now try to take this opportunity to point out that it
printed "got <function0>", so it must be a function. Well, I've got
two words for you: eta expansion. When you wrote "f _", Scala created
a function for you. That's what it does when you write "f _". You'd
have a stronger argument if you decompiled doFunction and showed that
it expected a function, but that's implementation, and, in fact, it is
just an interface name.

So, let's proceed:

doSam(body2sam({ println("1"); println("2") }))

becomes, because of body2sam's by-name parameter,

doSam(new SAM {
override def onSam = { println("1"); println("2") }
})


Finally, this:

doSam { println("1"); println("2") }

So, doSam does not receive a parameter by name, which means "{
println("1"); println("2") }" gets evaluated before being passed. It's
value is defined to be the value of the last statement, println("2").
Since it is not a SAM, Scala checks if it conforms to SAM through an
implicit conversion (or other means), which, in fact, it does. So it
becomes:

doSam { println("1"); body2sam(println("2")) }

All of which makes perfect sense and, while might be surprising the
first time you see it, can be easily deduced from the specification.
But only if you do pay attention to the specification, and stop
thinking of "block of code" as some sort of equivalent of a function,
never mind confusing by-name parameters with functions.

>
> AFAICT, the "couple of statements inside a scope delimiter" can indeed be a
> function, as the call to doFunction shows.
> It's quite odd that the same syntax (doFunction { ... } vs. doSam { ... })
> results in very different behavior depending on whether an implicit
> conversion is involved.

There's no oddity here -- it only looks odd because of your
presumption that there's a function here.

Yoav Abrahami

unread,
Jul 25, 2011, 4:58:31 AM7/25/11
to scala-language
Hi Daniel, Roland,
I think the example in https://gist.github.com/1101709 says it all.

doSam(body2sam({ println("1"); println("2") }))
// got foo.Foo$$anon$1@2b86c6b2
// 1 2 1 2

doSam { println("1"); println("2") }
// 1
// got foo.Foo$$anon$1@416b13c7
// 2 2

the two functions above should (for any reasonable reader) produce the
same result. Why should the use of implicit conversion produce
something different?

If, as Roland says, this case is too complicated for the compiler, it
should be excluded - should not compile.
Something like saying "implicit conversion are not supported for
delayed evaluation of Unit parameters because of potential ambiguity"

However, having the same code (from the point of view of a developer)
do two different things is really bad for a programming language - it
is one of those things that was really bad in C++ (namely multiple
inheritance which was so bad it too 25 years for developers to
overcome). A programming language should not be ambiguous, ever.

When I say ambiguous, I mean from the point of view of the developer,
not the compiler
:-)

On Jul 25, 2:09 am, Daniel Sobral <dcsob...@gmail.com> wrote:
> On Sat, Jul 23, 2011 at 17:44, Stephen Haberman
>

Johannes Rudolph

unread,
Jul 25, 2011, 6:01:11 AM7/25/11
to scala-l...@googlegroups.com
On Mon, Jul 25, 2011 at 10:58 AM, Yoav Abrahami <yoa...@gmail.com> wrote:
> the two functions above should (for any reasonable reader) produce the
> same result. Why should the use of implicit conversion produce
> something different?

Actually for those cases the reader can't expect to much as long as
implicits and by-name parameters are concerned because at the
call-site those are completely transparent. To understand a program
completely the reader has to know at least the signatures of the
callees and which implicits are in scope. With his knowledge of how
implicit conversions work he can then infer what is happening.

But those are just artifacts of a powerful, generic language where
libraries can (re-)define semantics to a certain degree.

I agree that implicits taking a by-name parameter are a potential
pitfall and seldom useful and if something can be done against this it
would probably be putting a warning at the definition site of an
implicit conversion with a by-name parameter.

--
Johannes

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

Daniel Sobral

unread,
Jul 25, 2011, 7:55:20 AM7/25/11
to scala-l...@googlegroups.com
On Mon, Jul 25, 2011 at 05:58, Yoav Abrahami <yoa...@gmail.com> wrote:
> Hi Daniel, Roland,
> I think the example in https://gist.github.com/1101709 says it all.
>
>    doSam(body2sam({ println("1"); println("2") }))
>    // got foo.Foo$$anon$1@2b86c6b2
>    // 1 2 1 2
>
>    doSam { println("1"); println("2") }
>    // 1
>    // got foo.Foo$$anon$1@416b13c7
>    // 2 2
>
> the two functions above should (for any reasonable reader) produce the
> same result. Why should the use of implicit conversion produce
> something different?

Because { println("1"); println("2") } is not a function!

Let me try this in a different way...

scala> { println("1"); println("2") } == println("2")
1
2
2
res0: Boolean = true

Do you consider this result (true) to be correct or incorrect?

Yoav Abrahami

unread,
Jul 25, 2011, 9:28:29 AM7/25/11
to scala-language
Hi Daniel,

My point is not that this code fragment is a function, block, or not.
My point is that in a programming language, a code fragment (by
whatever name) should be understood by the compiler and developers as
the same thing, always.
In this case, it is not.

by your logic,
doSam(body2sam({ println("1"); println("2") }))
// got foo.Foo$$anon$1@2b86c6b2
// 1 2 1 2
is wrong. it should print

// 1
// got foo.Foo$$anon$1@416b13c7
// 2 2

because, as you say, the code {println("1"); println("2")} is not a
function.




On Jul 25, 2:55 pm, Daniel Sobral <dcsob...@gmail.com> wrote:
> On Mon, Jul 25, 2011 at 05:58, Yoav Abrahami <yoa...@gmail.com> wrote:
> > Hi Daniel, Roland,
> > I think the example inhttps://gist.github.com/1101709says it all.

Roland Kuhn

unread,
Jul 25, 2011, 10:22:13 AM7/25/11
to scala-l...@googlegroups.com
Am 7/25/2011 3:28 PM, schrieb Yoav Abrahami:
> Hi Daniel,
>
> My point is not that this code fragment is a function, block, or not.
> My point is that in a programming language, a code fragment (by
> whatever name) should be understood by the compiler and developers as
> the same thing, always.
> In this case, it is not.
>
> by your logic,
> doSam(body2sam({ println("1"); println("2") }))
> // got foo.Foo$$anon$1@2b86c6b2
> // 1 2 1 2
> is wrong. it should print
>
> // 1
> // got foo.Foo$$anon$1@416b13c7
> // 2 2
>
> because, as you say, the code {println("1"); println("2")} is not a
> function.
>
Well, in this case it is! (see ch. 6.23 of the Scala Language Specification)

So, finally we arrive at the crucial point: as I tried to explain
earlier, this special exception is in place so that libraries can
provide methods which "feel like" control constructs. It is a conscious
design decision which is immensely important if you want to write nice
DSLs, one of Scala's central strengths.

Scala is a hammer which fits many a nail. But if your special nail
absolutely requires that { ... } never is a function, then by all means
choose a different tool.

Regards,

Roland

Tony Morris

unread,
Jul 25, 2011, 10:25:37 AM7/25/11
to scala-l...@googlegroups.com

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 25/07/11 23:28, Yoav Abrahami wrote:
> My point is that in a programming language, a code fragment (by
> whatever name) should be understood by the compiler and developers
> as the same thing, always.

Scala is not a lazy, pure functional programming language. Just sayin'

- --
Tony Morris
http://tmorris.net/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk4tfOEACgkQmnpgrYe6r6052wCfe8aJOzvN56pBltyQTid3UZsU
Yp4An24ZfWsNNBvOFHiqXa86B/aVbBpd
=fnZG
-----END PGP SIGNATURE-----

Josh Suereth

unread,
Jul 25, 2011, 10:29:49 AM7/25/11
to scala-l...@googlegroups.com
True.   That's not a bad thing if you're not looking for lazy, pure FP, but if you want lazy pure FP, it's going to be a bit more verbose to get it in Scala than a  language that fits that niche.

Also, the => A vs. () => A debate is a bit confusing at first to all of us in the language.  Daniel has a great explanation, but I'm not surprised it threw you for a loop at first.  It does for all of us.

Yoav Abrahami

unread,
Jul 25, 2011, 11:20:57 AM7/25/11
to scala-language
Roland, I think you misunderstand me.
I do not object for scala to handle a code fragment as a special case
as it does.

I do object for it to allow writing implicit conversions on it that
does something completely different.

I'd like Scala to be consistent in this regard, or disallow the
implicit conversion. If we have a special case, as you say here,
disallowing the implicit conversion is the right thing to do - as a
complementary special case.

Cheers,
Yoav

Stephen Haberman

unread,
Jul 25, 2011, 11:23:08 AM7/25/11
to scala-l...@googlegroups.com

> I have explained it in two different ways already, but I'll try again.

Thanks for taking the time to do so.

> Remember, first, that "=> Unit" is *not* a function.

Hm...okay, I guess that makes sense.

I still find myself tempted to think of them that way, especially for
DSLs and custom control structures where they're used (abused?) to get
syntactically-cheap functions, e.g.:

def main(args: Array[String]): Unit = {
bar { println("1"); println("2") }
bar { _ => println("1"); println("2") }
bar { s => println(s); println(s) }
}
def bar(f: String => Unit): Unit = f("hi")
def bar(f: => Unit): Unit = bar(_ => f)

Where I want the first bar call to be considered, effectively, as a
function that ignores its parameter. Here it works as expected, and is
what I was attempting to emulate against an API that takes a SAM.
Pimping the API seems to be the better way to go.

- Stephen

Daniel Sobral

unread,
Jul 25, 2011, 11:27:07 AM7/25/11
to scala-l...@googlegroups.com
On Mon, Jul 25, 2011 at 10:28, Yoav Abrahami <yoa...@gmail.com> wrote:
> Hi Daniel,
>
> My point is not that this code fragment is a function, block, or not.
> My point is that in a programming language, a code fragment (by
> whatever name) should be understood by the compiler and developers as
> the same thing, always.
> In this case, it is not.
>
> by your logic,
> doSam(body2sam({ println("1"); println("2") }))
> // got foo.Foo$$anon$1@2b86c6b2
> // 1 2 1 2
> is wrong. it should print
>
> // 1
> // got foo.Foo$$anon$1@416b13c7
> // 2 2
>
> because, as you say, the code {println("1"); println("2")} is not a
> function.

But body2sam receives a parameter by name -- you can't use by name
parameters and ignore how they work. You are being explicit in that
println("1") is part of it. Implicitly, it becomes:

{ println("1"); body2sam(println("2")) }

This is all according to the rules. The problem is not with the rules,
the problem is with your expectation that body2sam would apply over
the whole block, instead of its value. And that expectation only
exists because you insist of thinking of the block as a kind of "block
of code" object.

Daniel Sobral

unread,
Jul 25, 2011, 11:37:41 AM7/25/11
to scala-l...@googlegroups.com
On Mon, Jul 25, 2011 at 12:23, Stephen Haberman
<stephen....@gmail.com> wrote:
>
> Where I want the first bar call to be considered, effectively, as a
> function that ignores its parameter. Here it works as expected, and is
> what I was attempting to emulate against an API that takes a SAM.
> Pimping the API seems to be the better way to go.

Don't go overboard with implicit conversions. It costs very little to
put a "bar" in front of the block, so do that.

Roland Kuhn

unread,
Jul 25, 2011, 1:22:05 PM7/25/11
to scala-l...@googlegroups.com
[small erratum: I mixed up the references, it is in fact section 4.6.1
of the SLS]

Yes, there must have been some misunderstanding on my part along the
way: allowing by-name parameters on implicit conversions is
questionable. So, as long as by-name parameters in general remain
supported, we are in agreement ;-)

BTW: can someone think of a non-confusing use-case for conversions
taking by-name arguments?

Regards,

Roland

Mark Harrah

unread,
Jul 25, 2011, 1:29:44 PM7/25/11
to scala-l...@googlegroups.com
On Mon, 25 Jul 2011 12:01:11 +0200
Johannes Rudolph <johannes...@googlemail.com> wrote:
> I agree that implicits taking a by-name parameter are a potential
> pitfall and seldom useful and if something can be done against this it
> would probably be putting a warning at the definition site of an
> implicit conversion with a by-name parameter.

https://issues.scala-lang.org/browse/SI-3237

-Mark

Ðavîd Låndïs

unread,
Jul 25, 2011, 2:11:13 PM7/25/11
to scala-l...@googlegroups.com
On Mon, Jul 25, 2011 at 10:29 AM, Josh Suereth <joshua....@gmail.com> wrote:
> Also, the => A vs. () => A debate is a bit confusing at first to all of us
> in the language.  Daniel has a great explanation, but I'm not surprised it
> threw you for a loop at first.  It does for all of us.
>

Watch out, you almost said it was "complex". I new here, but even I
know better than that ;)

Yoav Abrahami

unread,
Jul 25, 2011, 4:35:21 PM7/25/11
to scala-language
Daniel,

I think your still not getting my point.

I agree - there is no code block.
I agree - there is no function.

However, I do not agree that
body2sam({ println("1"); println("2") } )

is equivalent to
{ println("1"); body2sam(println("2")) }

because they print something completely different!

please run the code
doSam(body2sam({ println("1"); println("2") }))
// got foo.Foo$$anon$1@2b86c6b2
// 1 2 1 2

then run the code
doSam({ println("1"); body2sam(println("2")) }))
// got foo.Foo$$anon$1@2b86c6b2
// 1 2 2

those are two different things.

My observation is that if we apply body2sam as an implicit conversion
on {println("1"); println("2")}, the compiler sees code written as the
second example, not the first.
I understand that the compiler has a hard life in this case, because
when it looks were the body2sam conversion fits the code, it finds two
places.
adding body2sam to the code {println("1"); println("2")} can be done
as
body2sam({println("1"); println("2")})
or
{println("1"); body2sam(println("2"))}
And those two ways are different!
In such a case, we have ambiguity and the compiler must issue a
compilation error. The fact that it does not means there is something
broken with the Scala compiler.

Thanks for helping me clarify the issue.
Cheers,
Yoav



by your logic,
doSam(body2sam({ println("1"); println("2") }))
// got foo.Foo$$anon$1@2b86c6b2
// 1 2 1 2
is wrong. it should print
// 1
// got foo.Foo$$anon$1@416b13c7
// 2 2

Daniel Sobral

unread,
Jul 25, 2011, 4:50:43 PM7/25/11
to scala-l...@googlegroups.com
On Mon, Jul 25, 2011 at 17:35, Yoav Abrahami <yoa...@gmail.com> wrote:
> Daniel,
>
> I think your still not getting my point.
>
> I agree - there is no code block.
> I agree - there is no function.
>
> However, I do not agree that
> body2sam({ println("1"); println("2") } )
>
> is equivalent to
> { println("1"); body2sam(println("2")) }
>
> because they print something completely different!

I'm not saying they are the same, I'm saying they are different. When
you use implicits, it is the latter version that is used. When you do
it explicitly, you can do it any way you want, and the example
happened to use the former.

> My observation is that if we apply body2sam as an implicit conversion
> on {println("1"); println("2")}, the compiler sees code written as the
> second example, not the first.
> I understand that the compiler has a hard life in this case, because
> when it looks were the body2sam conversion fits the code, it finds two
> places.
> adding body2sam to the code {println("1"); println("2")} can be done
> as
> body2sam({println("1"); println("2")})
> or
> {println("1"); body2sam(println("2"))}
> And those two ways are different!
> In such a case, we have ambiguity and the compiler must issue a
> compilation error. The fact that it does not means there is something
> broken with the Scala compiler.

There are many ways things can be written in different manners with
different meanings and still be valid, why would this cause a warning?
There's no ambiguity here -- there's need of a Unit, and the last
statement of the block provides one. Since the parameter is by name,
it passes that statement by name.

The only "ambiguity" here is "I'd like it to do something else." Well,
it doesn't, but it is not ambiguous.

Tony Morris

unread,
Jul 25, 2011, 5:25:53 PM7/25/11
to scala-l...@googlegroups.com

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

IO is associative but does not commute.

Yoav, I suggest trying your examples in a language where the
type-checker makes some of your observations more apparent. You are
right of course, but it can be made more obvious with a type checker
that delineates between these differents type of value.

- --
Tony Morris
http://tmorris.net/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk4t32AACgkQmnpgrYe6r60amwCglMj/LSpkS249MilmVv1wlvs3
Y+IAn1bvKPgMASJLz/YvXbGeoDTVQkpz
=RVW0
-----END PGP SIGNATURE-----

Reply all
Reply to author
Forward
0 new messages