Is there a way in Scala to forbid using named arguments for a function?
Example:
def func(num: Int, power: Int) = math.pow(num, power)
func(3, 2) // OK
func(num = 3, power = 2) // Forbidden
You could use a function literal:
val func = (num: Int, power: Int) => math.pow(num, power)
func(3, 2)
func(num = 3, power = 2) // "error: not found: value num"
(Although Function2's apply still has argument names:)
func(v1 = 3, v2 = 2)
Here is what I would suggest:
apm#mara:~$ scalac -deprecation -Xfatal-warnings
Welcome to Scala version 2.11.0-20130923-052707-7d570b54c3 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def f(#deprecatedName('x) x: Int) = 2 * x
f: (x: Int)Int
scala> f(3)
res0: Int = 6
scala> f(x = 4)
<console>:9: warning: naming parameter x has been deprecated.
f(x = 4)
^
error: No warnings can be incurred under -Xfatal-warnings.
Unfortunately, it doesn't work that way today, although it's an easy tweak.
The error you'd see today is:
error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not).
Does it make sense to deprecate the current name of a parameter?
The JavaDoc says:
A program element annotated #Deprecated is one that programmers are
discouraged from using, typically because it is dangerous, or because
a better alternative exists.
If you can motivate discouraging users from using named arguments when calling a function, then you should be able to deprecate that usage outright.
Maybe there is better wording for the new error:
warning: that parameter is he-who-must-not-be-named!
Related
From Magnet Pattern article, I found implicit conversion special pattern.
What is interesting is that this approach also works for “overloads” with more than one parameter just as well as different return types. If you call complete with several arguments the compiler looks for an implicit conversion that can produce a magnet instance from a tuple wrapping all arguments. This way overloads with up to 22 parameters (the maximum arity of tuples in scala) can be supported.
scala> def printInt(i: Int) = println(i)
printInt: (i: Int)Unit
scala> printInt(10)
10
scala> printInt(10, 20)
^
error: too many arguments (2) for method printInt: (i: Int)Unit
scala> implicit def toOneInt(is: (Int, Int)): Int = is._1 + is._2
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
toOneInt: (is: (Int, Int))Int
scala> printInt((10, 20))
30
scala> printInt(10, 20)
30
printInt((10, 20)) is boring me, but printInt(10, 20) is awesome!
Then I sought the specification of this special pattern from Scala Language Specification (2.12).
However I cannot find it yet and finally give up.
Could anyone show me where is the special pattern from Scala Language Specification (2.12) ?
By xuwei_k help, finally I reached name of the feature "adapted args" or "auto tupling".
For further details, Scala Puzzle(jp) was so helpful.
And also Scala Puzzlers shows [SI-3583] Spec doesn't mention automatic tupling - Scala.
Then, the answer is nowhere yet.
object solution extends App {
'n = 5
}
It gives the compile time Error: value update is not a member of object Symbol
println('n = 'n) which is understandable. Because literals are the fixed values in the source code. But what is the reason the above syntax is valid?
The reason the syntax is valid is … well … because it is:
implicit class UpdateableSymbol(val s: Symbol.type) extends AnyVal {
def update[A](s: String, v: A) = println(s"`Symbol.update` called with s = $s and v = $v")
}
'n = 5
// `Symbol.update` called with s = n and v = 5
As you can see, there is absolutely nothing wrong with the syntax, so why should it be invalid? The error message tells you what the problem is: you are calling Symbol.update but that doesn't exist. A missing method is not a syntactic error, it is a semantic error.
Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> reify('n)
res0: reflect.runtime.universe.Expr[Symbol] = Expr[Symbol](Symbol.apply("n"))
scala> val a = 'n
a: Symbol = 'n
scala> a = 5
<console>:15: error: reassignment to val
a = 5
^
scala> a.update(5)
<console>:16: error: value update is not a member of Symbol
a.update(5)
^
Desugar it, and you will find the answer.
In Scala, operators are methods.
For Symbol, see https://github.com/scala/scala/blob/2.13.x/src/library/scala/Symbol.scala
I have a function as follows:
def foo(sequence: Seq): Unit = {
...
bar.select(sequence);
}
I obtained an error, overloaded method value select with alternatives. I'm new to Scala's syntax, and I don't know the exact term, so I have been searching online without any results.
In particular, Scala appears to be confused as to which of the select method I am calling. From the documentation, there are 2 select methods (Source: https://spark.apache.org/docs/1.5.2/api/scala/index.html#org.apache.spark.sql.DataFrame)
I have tried the following, but perhaps because I am not familiar with the syntax, I was not able to succeed:
bar.select(sequence.asInstanceOf[Seq[Column]]);
How do I tell Scala that I want it to use select(cols: Column*) instead of alternatives? And if it is fine, could the answer include what concept this is - just so I can tag it properly, and learn something new.
Declare your foo method like this and use _*. As shown below
def foo(sequence: Seq[Column]): Unit = {
bar.select(sequence: _*)
}
Explanation select takes var args. When you want to pass Seq to a method which takes var args you have to explicitly say _* So that compiler can accept the Seq as var args.
Scala REPL example
scala> def foo(a: Int*) = 1
foo: (a: Int*)Int
scala> foo(Seq(1, 2))
<console>:13: error: type mismatch;
found : Seq[Int]
required: Int
foo(Seq(1, 2))
^
scala> foo(Seq(1, 2): _*)
res1: Int = 1
notice calling foo(Seq(1, 2) gives a compilation error this error can be fixed if we guide the compiler by giving type explicitly as _*
scala> val alist = List(1,2,3,4,5)
alist: List[Int] = List(1, 2, 3, 4, 5)
scala> alist filter { 2.< }
res2: List[Int] = List(3, 4, 5)
scala> alist filter { 2 < }
res3: List[Int] = List(3, 4, 5)
scala> alist filter { > 3 }
<console>:1: error: ';' expected but integer literal found.
alist filter { > 3 }
Why would { 2.< } and {2 <} work? I think at least I should write { 2 < _ } right?
A method that requires no arguments, you can alternatively leave off the dot and use postfix operator notation:
scala> val s = "Hello, world!"
s: java.lang.String = Hello, world!
scala> s toLowerCase
res4: java.lang.String = hello, world!
But here, < method is not those kinds of methods which requires no arguments right?
Can you point me what is this usage?
The reason for this is that 2 is an object, so if you write 2.< or 2 < (which are actually the same in Scala), then you are calling a method < on the object 2.
If you just write < or > the compiler will look for such a method in the local scope, but won't find one. Similarly, writing > 3, the compiler needs a method > available, which isn't.
You can also see this behavior in the console directly:
scala> 3.<
<console>:8: error: ambiguous reference to overloaded definition,
both method < in class Double of type (x: Char)Boolean
and method < in class Double of type (x: Short)Boolean
match expected type ?
3.<
^
As you can see, there are several implicts defined, which turn 3 into an object of a class that defines a < method. So this works in principal, but cannot stand on its own. It works, however, if you have more type information like in your example.
Contrast this with the following:
scala> <(3)
<console>:8: error: not found: value <
<(3)
^
Here you can see the compiler looking for a standalone < somewhere. Note that the error message says value, but this still means it could be a function, as the value type may be (Int, Int) => Boolean or something like that.
What is happening is an Eta Expansion (6.26.5):
Eta-expansion converts an expression of method type to an equivalent
expression of function type.
In this case, 2 < is a method type: (one of) the method < on Int. However, filter expects a function type. In such a case, Scala does automatic eta expansion.
Note that, because the type expected by filter is known, it can correctly infer what 2 < method is being called.
2.< refers to the method < of object 2, whereas 2.<(_) returns a new function with one argument. The latter is a shortcut for (is expanded to) (x: Int) => 2 < x where the type Int was inferred by the scala compiler from the type of the elements of alist.
> 3 in your case does not refer to any method or object of any object. > is a legal scala identifier (for a method, function or object), but 3 is not a legal identifier (it begins with a digit). > a could be a reference a member a of object > (>.a). But neither of those exist in your example. _ > 3 however returns a new function with one argument, which you could also write (x: Int) => x > 3.
This is in essence the same than Daniel C. Sobral's answer and incrop's comment to Frank's answer, but less formal and with more examples. Hope this helps get an intuition.
I'm using scala-2.8.1 and scalaz-5.0. Can anyone explain exactly why a PartialApply1Of2 can be inferrred in the one case but not in the other?
scala> 1.success[String] <|*|> "Bah".fail[Int]
res1: scalaz.Validation[String,(Int, Int)] = Failure(Bah)
That worked even though (as has been asked before!) the method <|*|> is on MA which has one type parameter, not two (as Validation has). I cannot get unicode working in my IDEA REPL, so here goes:
object testy {
def main(args: Array[String]) {
import scalaz._
import Scalaz._
val ps = NonEmptyList(1.success[String], "Bah".fail[Int])
val res = ps.∘∘((_ : Int) % 2 == 0) //DOES NOT COMPILE
println(res)
}
}
I can provide a specific type to the call and all is good. Why can scalac not infer this?
ps.∘∘[PartialApply1Of2[Validation, String]#Apply, Int, Boolean]((_ : Int) % 2 == 0)
In my REPL, this actually causes a scalac error, rather than a sensible error message
In the first case, the implicit view ValidationMA is inferred, and the the type argument Int is inferred:
Scalaz.ValidationMA(1.success[String]).<|*|>[Int]("Bah".fail[Int])
In the second case, the type argument to the method ∘∘ cannot be inferred, until #2712 is tackled.
I suspect that the scalac internal error you encountered is related to #2741 / #4079. If so, you can rewrite it with a Type Lambda to workaround the error.
ps.∘∘[({type X[a]=Validation[String, a]})#X, Int, Boolean]((_ : Int) % 2 == 0)
I recommend using this syntax instead of PartialApplyNofM in all cases, as I find it more readable. With a recent build of IntelliJ, you can even enable a code folding (Settings, Code Style, Scala, Folding, Type Lambas), to hide some syntactic clutter.