Here is my “pragmatic” answer: you usually use currying as more “convention” than anything else meaningful. This is very convenient when your last parameter is a call by name parameter (for example : => Boolean ):
def transaction(conn: Connection)(codeToExecuteInTransaction : => Boolean) = { conn.startTransaction // start transaction val booleanResult = codeToExecuteInTransaction //invoke the code block they passed in //deal with errors and rollback if necessary, or commit //return connection to connection pool }
What it is: "I have a function called transaction , its first parameter is Connection, and its second parameter will be a code block."
This allows us to use this method like this (using "I can use curly braces instead of the brace rule"):
transaction(myConn) {
If you did not use this transaction method, it would look rather unnatural:
transaction(myConn, {
How about implicit ? Yes, this may seem like a very ambiguous design, but you get used to it after a while, and the nice thing about implicit functions is that they have domain definition rules. Thus, this means that for production you can define an implicit function to get this database connection from the PROD database, but in your integration test you will define an implicit function that will replace the PROD version, and it will be used to get the connection from the database DEV data instead for use in your test.
As an example, how about adding an implicit parameter to a transaction method?
def transaction(implicit conn: Connection)(codeToExecuteInTransaction : => Boolean) = { }
Now, assuming I have an implicit function somewhere in my code base that returns a connection, for example:
def implicit getConnectionFromPool() : Connection = { ...}
I can execute the transaction method as follows:
transaction { //code to execute in transaction }
and Scala will translate this:
transaction(getConnectionFromPool) { //code to execute in transaction }
In general, Implicits is a pretty good way of not forcing the developer to provide a value for the required parameter when this parameter is 99% of the time, which will be the same everywhere you use this function. For 1% of the time, when you need another connection, you can provide your own connection by passing a value instead of letting Scala determine which implicit function provides the value.