SimpleDateFormat getting BoxedUnit

160 views
Skip to first unread message

ma...@jakubjanecek.com

unread,
Aug 6, 2013, 10:08:40 AM8/6/13
to scala...@googlegroups.com
Hello,

I encountered a strange behavior of Scala when using SimpleDateFormat. In my opinion it is a bug. It is easily reproducible with this code:

import java.text.SimpleDateFormat
val sdf = new SimpleDateFormat("yyyyMMdd-HH0000")
sdf.format()

I think this code is erroneous and should not compile because there is no method format with 0 arguments in SimpleDateFormat. However, the code compiles and ends up in "java.lang.IllegalArgumentException: Cannot format given Object as a Date".

java.lang.IllegalArgumentException: Cannot format given Object as a Date
at java.text.DateFormat.format(DateFormat.java:301)
at java.text.Format.format(Format.java:157)
at .<init>(<console>:10)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983)
at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568)
at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:745)
at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:790)
at scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:702)
at scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:566)
at scala.tools.nsc.interpreter.ILoop.innerLoop$1(ILoop.scala:573)
at scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:576)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply$mcZ$sp(ILoop.scala:867)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:822)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:822)
at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
at scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:822)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

I debugged the code and found out that an instance of BoxedUnit is passed in.

Can anyone please explain me why? Or is it really a bug of Scala compiler?

Thanks.

--
Jakub Janeček

Simon Ochsenreither

unread,
Aug 6, 2013, 12:35:37 PM8/6/13
to scala...@googlegroups.com
Hi Jakub,

the issue is that the () gets treated as the Unit value.

See val unit = ().

Try compiling with -Xlint or -Ywarn-adapted-args:

10: warning: Adapting argument list by inserting (): leaky (Object-receiving) target makes this especially dangerous.
        signature: Format.format(x$1: Any): String
  given arguments: <none>
 after adaptation: Format.format((): Unit)
              sdf.format()
                        ^


I haven't seen an example where this “feature” has been a good idea.

I hope that helps a bit!

Bye,

Simon

Som Snytt

unread,
Aug 6, 2013, 1:30:54 PM8/6/13
to scala-user
Also, -Yno-adapted-args

Would an annotation be feasible?  @unadapted

Maybe with a field to say which adaptations are left undone, at either call or definition site.

@unadapted(unitInsertion)

@unadapted(disallow=unitInsertion|tupling)

I realize now that it's called Any because it's Anathema, or Anythema.

scala> s"Hello, $_"()
<console>:8: warning: Adapting argument list by inserting (): this is unlikely to be what you want.
        signature: Function1.apply(v1: T1): R
  given arguments: <none>
 after adaptation: Function1((): Unit)
              s"Hello, $_"()
                          ^
res1: String = Hello, ()



--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Simon Ochsenreither

unread,
Aug 6, 2013, 3:01:02 PM8/6/13
to scala...@googlegroups.com
It would probably better to just get rid of it.

I really have to find that mail to scala-internals where I brought that up some time ago ... not sure what the result of the discussion was.

Simon Ochsenreither

unread,
Aug 6, 2013, 3:04:11 PM8/6/13
to scala...@googlegroups.com

ma...@jakubjanecek.com

unread,
Aug 7, 2013, 4:37:57 AM8/7/13
to scala...@googlegroups.com
Thank you all for your replies.

But can anyone explain what is the reasoning behind such feature? Because I really can't imagine why this would be helpful. In my case it made the code buggy and I didn't even know about it!

On Tuesday, August 6, 2013 9:04:11 PM UTC+2, Simon Ochsenreither wrote:
Found it: https://groups.google.com/d/topic/scala-internals/4RMEZGObPm4/discussion

Som Snytt

unread,
Aug 7, 2013, 6:34:17 AM8/7/13
to ma...@jakubjanecek.com, scala-user

If you like one of these applications, you like them all.  If applying N args is like applying a TupleN, then 0 args is like a Tuple0, the empty tuple or nuple or uniple or unipple or unittuple.

It's like going to a mind-reader or medium to compile your code.  "I sense a presence in this room.  Does it take an integer?  No, no, the spirit is unhappy.  Does it take two integers?  Does it take... a pair of integers?"  "Yes, yes, that's my function!  How did you know?  What else can you tell me?"

The real question is why would anyone have a method that takes Any? How is that helpful?

Except that there is puzzling behavior of method overload resolution that relies on this puzzling behavior, so you can't change it without breaking something on scalapuzzlers.com.

scala> def f(a: Any) = a.toString
f: (a: Any)String

scala> f()
res3: String = ()

scala> def g(b: (Int,Int)) = b._1 + b._2
g: (b: (Int, Int))Int

scala> g(1,2)
res4: Int = 3

scala> f(1,2)
res6: String = (1,2)



--

Simon Ochsenreither

unread,
Aug 7, 2013, 7:12:37 AM8/7/13
to scala...@googlegroups.com
Hi Jakub,


But can anyone explain what is the reasoning behind such feature?

I think the only good answer to this is to look for the commit which introduced this “feature” and ask the author. I expect that it was added a long time ago.
 
Because I really can't imagine why this would be helpful. In my case it made the code buggy and I didn't even know about it!

I totally agree. Adriaan answered in the other thread that a new tool, dbuild, will allow to switch off this “feature” and rebuild pretty much every Scala library against the new compiler. This will allow us to see whether there is any actual (and useful) usage of this feature in the wild. With those statistics available, it will be much easier to get rid of this feature.

Bye,

Simon
Reply all
Reply to author
Forward
0 new messages