Named parameters lead to maintenance problems and inferior readability? - scala

With named parameters like
def f(x : Int = 1, y : Int = 2) = x * y
your parameter names become part of the interface
f(x=3)
Now if you want to change the parameter names locally, you are forced to perserve the public name of the parameter:
def f(x : Int = 1, y : Int = 2) = {
val (a,b) = (x,y)
a * b
}
If this a real problem? Is there a syntax to support this directly? Who do other languages handle this?
A small illustration of the problems you can run into if you switch parameter names, as suggested by Jon.
trait X{ def f(x : Int, y : Int) }
class A extends X{
override def f(y : Int, x : Int) = println("" + y + x)
}
val a = new A
scala> a.f(x = 1, y = 2)
21
scala> (a : X).f(x = 1, y = 2)
12

Yes, the parameter name is effectively part of the public interface. This is a "problem" for any language which has named arguments - or indeed produces code which is consumed by languages supporting named arguments. Sometimes this isn't well understood.
For example, C# 3 doesn't support named arguments - but VB does. So if you create a library in C# 3, someone builds against it in VB, then changing parameter names counts as a breaking change.
Ultimately some of this will be handled by refactoring tools, but it boils down to the same sort of caution as with any other aspect of a public API... you need to be very cautious.
You should also be very cautious when overriding a method with parameters - use the same parameter names as the original method, or you could cause some very subtle issues. (In particular, switching round the names of parameters would be very evil...)

I don't know about the "inferior readability" part of your title. The few times I used named parameters, it was to provide default values like increment:Int = 100000, maxCount:Int = 1000000. I think it helps readability when you have to changed on value where you call the function.

Related

Scala: currying vs closure

I can use closure to define function like this:
def product(x: Int) = (y: Int) => x * y
val productBy3 = product(3)
println(productBy3(6)) // 18
OR, using currying:
def curriedProduct(x: Int)(y: Int) = x * y
val productBy3 = curriedProduct(3)_
println(productBy3(6)) // 18
Any advantage/disadvantage one approach has over other?
The first is an example of a method returning a function. The second is an example of a method with multiple parameter lists.
The way you use them, there is no difference.
When called as product(3)(6), the second may be a bit faster, but not to an extent that would normally be a concern.
I would use the first form when the expected way to call it would be with product(3), and use the second form if the normal way to call it would be product(3)(6).
Lastly, I'd like to suggest the possibility of
def product(i: Int, j: Int) = i * j
val productBy3 = product(3, _)
println(productBy3(6)) //18
I don't really see any upsides of using the second form instead of either this alternative or the first alternative in this situation. Using multiple parameter lists may help type inference in scala 2 (see https://docs.scala-lang.org/tour/multiple-parameter-lists.html), but there is no problematic inference here anyway.

Passing DEFAULTS args in function scala

I'm trying to pass a default args in a function like we can do in method ..But im getting an error. Is it possible to pass a default args / named args to a function like method?
Is it possible to pass named arguments in function while calling it ?
This only works for methods (which are defined with def).
def func(i: Int = 2) = i
However, here is somewhat of a "hack" to do it regardless.
You can use a curried function here
def sum1(a:Int=2)(b:Int) = a+b
sum1(33)
Hope this answers your question.
var f(i:Int=2,j:Int) => i + j
This does not work. If you want to define a lambda, try this
val f = (i:Int,j:Int) => i + j
This is the correct approach. Also you cannot assign default values in lambda. You need to define methods with def keyword. Try this:
def f(i:Int, j:Int=2) = i + j
Parameter with default value should be the last parameter because scala compiler will scan values from left-right. It'll only use default values if there are missing ones. In above code f(1) will produce 3 because j will use 2 as default value. So use the compulsory arguments in the left side and the ones with default values on right. Hope this helps
Explained here: In Scala, can you make an anonymous function have a default argument?
Named arguments work with function definitions. Parameters with defaults don't need to be given:
class my
{
def f(i:Int = 2, j: Int) = i + j
}
var my = new my()
my.f(j = 1) // i = 2, j = 1
my.f(i = 3, j = 1) // i = 3, j = 1
my.f(3, 1) // i = 3, j = 1

Scala Implicit Conversion Function Name Clashes

I am working with a simple complex number case class in Scala and would like to create an add function that works between complex numbers, doubles and ints. Below is a simple example of a working solution:
case class Complex(re: Double, im: Double)
implicit def toComplex[A](n: A)(implicit f: A => Double): Complex = Complex(n, 0)
implicit class NumberWithAdd[A](n: A)(implicit f: A => Complex) {
def add(m: Complex) = Complex(n.re + m.re, n.im + m.im)
}
Note I am deliberately not including the add function in the complex case class. Using the above I can do all of this:
scala> val z = Complex(1, 2); val w = Complex(2, 3)
z: Complex = Complex(1.0,2.0)
w: Complex = Complex(2.0,3.0)
scala> z add w
res5: Complex = Complex(3.0,5.0)
scala> z add 1
res6: Complex = Complex(2.0,2.0)
scala> 1 add z
res7: Complex = Complex(2.0,2.0)
I'd like to use '+' instead of 'add, but however this does not work. I get the following error:
Error:(14, 4) value + is not a member of A$A288.this.Complex
z + 1
^
Both z + w and 1 + z still work however.
What I'd like to know is why does changing the function name from 'add' to '+' break this? Is there an alternate route to getting this functionality (without simply putting the add function in the complex case class)? Any help would be appreciated.
Edit - Motivation
I'm playing around with monoids and other algebraic structures. I would like to be able to generalise the '...WithAdd' function to automatically work for any class that has a corresponding monoid:
trait Monoid[A] {
val identity: A
def op(x: A, y: A): A
}
implicit class withOp[A](n: A)(implicit val monoid: Monoid[A]) {
def +(m: A): A = monoid.op(n, m)
}
case class Complex(re: Double, im: Double) {
override def toString: String = re + " + " + im + "i"
}
class ComplexMonoid extends Monoid[Complex] {
val identity = Complex(0, 0)
def op(z: Complex, w: Complex): Complex = {
Complex(z.re + w.re, z.im + w.im)
}
}
implicit val complexMonoid = new ComplexMonoid
Using the above I can now do Complex(1, 2) + Complex(3, 1) giving Complex = 4.0 + 3.0i. This is great for code reuse as I could now add extra functions to the Monoid and withAdd function (such as appling op n times to an element, giving the power function for multiplication) and it would work for any case class that has a corresponding monoid. It is only with complex numbers and trying to incorporate doubles, ints, etc., that I then run into the problem above.
I would use a regular class, not a case class. Then it would be easy to create methods to add or subtract these Complex numbers, like:
class Complex(val real : Double, val imag : Double) {
def +(that: Complex) =
new Complex(this.real + that.real, this.imag + that.imag)
def -(that: Complex) =
new Complex(this.real - that.real, this.imag - that.imag)
override def toString = real + " + " + imag + "i"
}
As the source page shows, it will now support something that looks like operator overloading (it's not, because + and - are functions and not operators).
The problem with implicit class NumberWithAdd and its method + is that the same method also exist in number classes such as Int and Double. The + method of NumberWithAdd basically allows you to start with a number that can be casted to Complex and add a Complex object to that first item. That is, the left hand value can be anything (as long as it can be converted) and the right hand value must be Complex.
That works great for w + z (no need to convert w) and 1 + z (implicit conversion for Int to Complex is available). It fails for z + 1 because + is not available in the class Complex .
Since z + 1 is actually z.+(1), Scala will look for other possible matches for +(i: Int) in classes that Complex can be converted into. It also checks NumberWithAdd, which does have a + function but that one required a Complex as right hand value. (It would match a function that requires an Int as right hand value.) There are other functions named + that do accept Int, but there's no conversion from Complex to what those functions want as left hand values.
The same definition of + does work when it's in the (case) class Complex. In that case, both w + z and z + 1 simply use that definition. The case 1 + z is now a little more complicated. Since Int does not have a function + that accepts a Complex value, Scala will find the one that does (in Complex) and determines whether or not it is possible to convert Int into Complex. That is possible using the implicit functions, the conversion takes place and the function is executed.
When the function + in the class NumberWithAdd is renamed add, there's no confusion with functions in Int because Int does not have a function +. So Scala will try harder to apply the function add and it will do the Int to Complex conversion. It will even do that conversion when you try 1 add 2.
Note: My explanations may not fully describe the actual inner workings.

scala currying by nested functions or by multiple parameter lists

In Scala, I can define a function with two parameter lists.
def myAdd(x :Int)(y :Int) = x + y
This makes it easy to define a partially applied function.
val plusFive = myAdd(5) _
But, I can accomplish something similar by defining and returning a nested function.
def myOtherAdd(x :Int) = {
def f(y :Int) = x + y
f _
}
Cosmetically, I've moved the underscore, but this still feels like currying.
val otherPlusFive = myOtherAdd(5)
What criteria should I use to prefer one approach over the other?
There are at least four ways to accomplish the same thing:
def myAddA(x: Int, y: Int) = x + y
val plusFiveA: Int => Int = myAddA(5,_)
def myAddB(x: Int)(y : Int) = x + y
val plusFiveB = myAddB(5) _
def myAddC(x: Int) = (y: Int) => x + y
val plusFiveC = myAddC(5)
def myAddD(x: Int) = {
def innerD(y: Int) = x + y
innerD _
}
val plusFiveD = myAddD(5)
You might want to know which is most efficient or which is the best style (for some non-performance based measure of best).
As far as efficiency goes, it turns out that all four are essentially equivalent. The first two cases actually emit exactly the same bytecode; the JVM doesn't know anything about multiple parameter lists, so once the compiler figures it out (you need to help it with a type annotation on the case A), it's all the same under the hood. The third case is also extremely close, but since it promises up front to return a function and specifies it on the spot, it can avoid one internal field. The fourth case is pretty much the same as the first two in terms of work done; it just does the conversion to Function1 inside the method instead of outside.
In terms of style, I suggest that B and C are the best ways to go, depending on what you're doing. If your primary use case is to create a function, not to call in-place with both parameter lists, then use C, because it tells you what it's going to do. (This version is also particularly familiar to people coming from Haskell, for instance.) On the other hand, if you are mostly going to call it in place but will only occasionally curry it, then use B. Again, it says more clearly what it's expected to do.
You could also do this:
def yetAnotherAdd(x: Int) = x + (_: Int)
You should choose the API based on intention. The main reason in Scala to have multiple parameter lists is to help type inference. For instance:
def f[A](x: A)(f: A => A) = ...
f(5)(_ + 5)
One can also use it to have multiple varargs, but I have never seen code like that. And, of course, there's the need for the implicit parameter list, but that's pretty much another matter.
Now, there are many ways you can have functions returning functions, which is pretty much what currying does. You should use them if the API should be thought of as a function which returns a function.
I think it is difficult to get any more precise than this.
Another benefit of having a method return a function directly (instead of using partial application) is that it leads to much cleaner code when using infix notation, allowing you to avoid a bucketload of parentheses and underscores in more complex expressions.
Consider:
val list = List(1,2,3,4)
def add1(a: Int)(b: Int) = a + b
list map { add1(5) _ }
//versus
def add2(a: Int) = a + (_: Int)
list map add2(5)

Declaring multiple variables in Scala

I'd like to use val to declare multiple variable like this:
val a = 1, b = 2, c = 3
But for whatever reason, it's a syntax error, so I ended up using either:
val a = 1
val b = 2
val c = 3
or
val a = 1; val b = 2; val c = 3;
I personally find both options overly verbose and kind of ugly.
Is there a better option?
Also, I know Scala is very well thought-out language, so why isn't the val a = 1, b = 2, c = 3 syntax allowed?
The trivial answer is to declare them as tuples:
val (a, b, c) = (1, 2, 3)
What might be interesting here is that this is based on pattern matching. What is actually happens is that you are constructing a tuple, and then, through pattern matching, assigning values to a, b and c.
Let's consider some other pattern matching examples to explore this a bit further:
val DatePattern = """(\d{4})-(\d\d)-(\d\d)""".r
val DatePattern(year, month, day) = "2009-12-30"
val List(rnd1, rnd2, rnd3) = List.fill(3)(scala.util.Random.nextInt(100))
val head :: tail = List.range(1, 10)
object ToInt {
def unapply(s: String) = try {
Some(s.toInt)
} catch {
case _ => None
}
}
val DatePattern(ToInt(year), ToInt(month), ToInt(day)) = "2010-01-01"
Just as a side note, the rnd example, in particular, may be written more simply, and without illustrating pattern matching, as shown below.
val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100)
Daniel's answer nicely sums up the correct way to do this, as well as why it works. Since he already covered that angle, I'll attempt to answer your broader question (regarding language design)...
Wherever possible, Scala strives to avoid adding language features in favor of handling things through existing mechanisms. For example, Scala doesn't include a break statement. However, it's almost trivial to roll one of your own as a library:
case object BreakException extends RuntimeException
def break = throw BreakException
def breakable(body: =>Unit) = try {
body
} catch {
case BreakException => ()
}
This can be used in the following way:
breakable {
while (true) {
if (atTheEnd) {
break
}
// do something normally
}
}
(note: this is included in the standard library for Scala 2.8)
Multiple assignment syntaxes such as are allowed by languages like Ruby (e.g. x = 1, y = 2, z = 3) fall into the category of "redundant syntax". When Scala already has a feature which enables a particular pattern, it avoids adding a new feature just to handle a special case of that pattern. In this case, Scala already has pattern matching (a general feature) which can be used to handle multiple assignment (by using the tuple trick outlined in other answers). There is no need for it to handle that particular special case in a separate way.
On a slightly different aside, it's worth noting that C's (and thus, Java's) multiple assignment syntax is also a special case of another, more general feature. Consider:
int x = y = z = 1;
This exploits the fact that assignment returns the value assigned in C-derivative languages (as well as the fact that assignment is right-associative). This is not the case in Scala. In Scala, assignment returns Unit. While this does have some annoying drawbacks, it is more theoretically valid as it emphasizes the side-effecting nature of assignment directly in its type.
I'll add one quirk here, because it hit myself and might help others.
When using pattern matching, s.a. in declaring multiple variables, don't use Capital names for the variables. They are treated as names of classes in pattern matching, and it applies here as well.
val (A,B)= (10,20) // won't work
println(A)
Error message does not really tell what's going on:
src/xxx.scala:6: error: not found: value A
val (A,B)= (10,20)
^
src/xxx.scala:6: error: not found: value B
val (A,B)= (10,20)
^
src/xxx.scala:7: error: not found: value A
println(A)
^
I thought `-ticking would solve the issue but for some reason does not seem to (not sure, why not):
val (`A`,`B`)= (10,20)
println(A)
Still the same errors even with that.
Please comment if you know how to use tuple-initialization pattern with capital variable names.
If all your variables are of the same type and take same initial value, you could do this.
val a, b, c: Int = 0;
It seems to work if you declare them in a tuple
scala> val (y, z, e) = (1, 2, 45)
y: Int = 1
z: Int = 2
e: Int = 45
scala> e
res1: Int = 45
Although I would probably go for individual statements. To me this looks clearer:
val y = 1
val z = 2
val e = 45
especially if the variables are meaningfully named.