4

The problem can be found in the following code:

      def debug[T](format: String, arg1:T, arg2:Any, args:Any*):T = {
        logger.debug(format, (arg1 :: arg2 :: args.toList).toArray)
        arg1
      }

Since what I pass as the second parameter is an array of Any's, this code should have called SLF4J's debug method

      public void debug(String format, Object[] argArray);

Yet

      public void debug(String format, Object arg);

ends up being called instead.

Let me give an example.

When I call

    debug("The four parameters are {} as String, {} as Integer, {} as String and {} as Integer.", "1", 2, "3", 4)

It logs

    DEBUG - The four parameters are [1, 2, 3, 4] as String, {} as Integer, {} as String and {} as Integer.

Instead of

    DEBUG - The four parameters are 1 as String, 2 as Integer, 3 as String and 4 as Integer.

NOTE1: I assumed the first call would work based on the scala.Array Scaladoc.

Represents polymorphic arrays. Array[T] is Scala's representation for Java's T[].

NOTE2: The code that originated my question can be found at https://github.com/alexmsmartins/UsefullScalaStuff/blob/master/src/main/scala/alexmsmartins/log/LoggerWrapper.scala

This is a small wrapper around slf4j that I use in my Scala projects.

  • You may be aware of http://software.clapper.org/grizzled-slf4j. It solves the performance issue the other way, which is to forgo the string interpolation in favour of passing a block returning a string which is only evaluated when required. – Duncan McGregor Nov 11 '11 at 07:48
  • I didn't knew this project at all. Never the less, my goal when doing this Wrapper was to make every method where it makes sense return a parameterized type T instead of Unit. To me this makes much more sense in a functional language like scala. Maybe I should look into it and take some ideas from their code. Thanks. – Alexandre Martins Nov 12 '11 at 15:41

2 Answers2

2

You need to use: (arg1 :: args2 :: args.toList).toSeq: _ * - see how StringLike.format works

Your choice of list creation will cause quite a bit of overhead in terms of object creation for a debug call (certainly it negates any benefit of reducing array creation IMHO)

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • You're absolutely right about the performance impact. Still I wanted to have a working wrapper that handles a vaiable number of parameters before worrying about that. But if you have a better way about how to go about it go ahead. I would appreciate it! :D – Alexandre Martins Nov 10 '11 at 18:40
  • Apparently not working -> overloaded method value debug with alternatives: [error] (org.slf4j.Marker,java.lang.String)Unit [error] (java.lang.String,java.lang.Throwable)Unit [error] (java.lang.String,Array[java.lang.Object])Unit [error] (java.lang.String,Any)Unit [error] cannot be applied to (String, Any) [error] logger.debug(format, (arg1 :: arg2 :: args.toList ___ Let me see if I can understand why. – Alexandre Martins Nov 10 '11 at 18:49
2

You are passing an Array[Any], not an Array[Object]. You could try changing your types from Any to AnyRef (in which case you'll not be able to pass AnyVal's such as Int). You could also call .asInstanceOf[Array[AnyRef]] after .toArray, which, in this one particular case, shouldn't give you trouble because the erasure is the same.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681