[slf4j-user] Scala and SLF4J

Brian Clapper bmc at clapper.org
Tue Apr 27 16:59:59 CEST 2010


[Seconded forwarded message, also originally a private response to Ceki. -bmc]

Ceki Gülcü wrote:
> Hello Brian,
> 
> I just came across AVSL and wanted to add it to the list of SLF4J
> implementations on the SLF4J web-site. It seems pretty obvious that AVSL
> is a native implementation of SLF4J. Would you concur?
> 
> By the way, I would really like to make logback more scala-friendly in
> particular with respect to configuration. Would you be interested in
> contributing?

Ceki,

Regarding Scala, you might also consider providing (or providing a pointer
to) a Scala-friendly SLF4J API.

The easiest way to make SLF4J more Scala-friendly is to provide a Scala API
that uses Scala's call-by-name capability. I don't know how much you know
about Scala, so I'll pretend you don't know much at all. If I'm explaining
something you already know, please accept my apologies.

Call-by-name is an interesting capability. It works like this.

Consider a normal function taking a string:

    def debug(msg: String) =
        if (debugEnabled)
            println(msg)

That's Scala syntax, of course, but it does what you expect from reading
it. That function suffers from the problem that SLF4J attempts to solve
with formats: Any arguments are calculated and expanded before the call,
which makes this call potentially expensive:

    debug("Problem with foo knob: " + calculateComplicatedThing())

But, in Scala, you can convert the "msg" parameter into an anonymous
function:

    def debug(msg: => String) =
        if (debugEnabled)
            println(msg)

In this version of debug(), "msg" is not a string. Instead, it's a function
returning a string. Thus, it is not actually invoked until the println()
call. This is what Scala calls "call-by-name" semantics.

Normally, with that function definition, you'd expect to have to call
debug() like this:

    debug( {"Problem with foo knob: " + calculateComplicatedThing()} )

The braces make it obvious that you're passing an anonymous function in.
However, Scala provides some syntactic sugar. If you call debug() like
this:

    debug("Problem with foo knob: " + calculateComplicatedThing())

Scala's type inferencer figures out that, really, the parameter is a
function body, so it acts as if the argument were surrounded by braces. You
don't actually have to supply the braces.

This is an obvious win. The interface look exactly the same for the caller,
but it behaves correctly, with delayed, not immediate, evaluation. Thus,
you get a nice, simple, natural interface, while still getting delayed
evaluation.

I wrote a Scala front-end for SLF4J that provides this interface for Scala,
delegating its calls to the underlying SLF4J API. It's here:

    http://bmc.github.com/grizzled-slf4j/

If you want to adapt it, or bundle it into SLF4J, I'll be glad to help.
-- 
-Brian

Brian Clapper, http://www.clapper.org/bmc/


More information about the slf4j-user mailing list