Decorator Pattern in Scala

Viewed 384

I have the following Code in Scala. I have a few questions regarding the functionality and syntax.

type Logger = String => Unit

type Decorator = Logger => Logger

  val uppercase: Decorator = 
    logger =>
      (msg: String) => logger(msg.toUpperCase)

  val info: Decorator =
    logger =>
      (msg:String) => logger("info " + msg)

Did I understand it correctly, that Decorator is the input of the ìnfo function?

Why is the declaration of the return type not necessary here?

Then I use the code like this:

val prefixUppercase = info(uppercase(println(_)))

Why can I pass println(_) to uppercase?

The uppercase function requires an argument of the type Decorator, which println() is clearly not.

Additonally I use println(_), but when I try to pass an named argument like this println(x) I get an error.

1 Answers

Did I understand it correctly, that Decorator is the input of the ìnfo function?

val info: Decorator =
  logger =>
    (msg:String) => logger("info " + msg)

No, Decorator is the type of info.

info is declared to be a function from Logger to Logger (which is what Decorator expands to).

val info: Decorator =  // info is a Decorator
                       // i.e. a function Logger => Logger

  logger =>            // so this makes logger a Logger
                       // (the input for the Decorator)

                       // what follows is the output of the Decorator
                       // i.e. another Logger
                       // i.e. a function String => Unit

    (msg:String) =>    // so this is that String input to the
                       // resulting (decorated) Logger  


       logger("info " + msg)  // and this is what our decorator does
                              // to the String to be logged:
                              // we prefix it with "info "
                              // and give it to the underlying logger

Why is the declaration of the return type not necessary here?

The return type is being declared (see above).

In general, Scala is quite good at infering types, so you do not actually need to declare the type of info if it can be derived from other known types, but

a) it is good practice to declare non-obvious types, especially on public values. This serves as documentation, speeds up compilation and can avoid errors (in case the inferred type is not what you wanted it helps tracking down the problem)

b) in your case, it is also the most straight-forward way to let the compiler know what type logger should have here. You would have to declare that somewhere else otherwise.

Why can I pass println(_) to uppercase? The uppercase function requires an argument of the type Decorator, which println() is clearly not.

uppercase does not require a Decorator, uppercase is a Decorator, meaning it is a function that takes a Logger and returns a Logger.

So it needs a Logger, which is a function that takes a String and does not return anything. println is such a function, so you can pass it to uppercase (as its Logger input argument).

I try to pass an named argument like this println(x) I get an error.

What is x in this case?

You need to create a Logger, meaning a function that takes a String and does not return anything special.

x => println(x) will do.

println(_) is short-hand for the same thing, and will do.

println(somethingElse) or println(123) are not functions that take a String anymore (they do not take any arguments anymore) so those are not Loggers.

Related