Is it possible to force named parameters in scala?

In some method, I would like to force the parameters to be named. The reason is the auto-generated code for which the order of the parameters is unspecified (and will remain that way).

The closest I can get

private val _forceNamed: Object = new Object()

def doSomething(forceNamed: Object = _forceNamed, arg1: String, arg2: String, ...): Unit = {
  if (forceNamed != _forceNamed) {
    throw Exception(something)
  }

  // actually do stuff
}

However, this just does not happen at run time, while something that fails at compile time will be much nicer.

+4
source share
5 answers

If you want to close the loophole for going through null, you can use the value class as a defender.

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Foo {
   import Foo._
   def foo(x: Bar = bar, a: String, b: String) = println(a + b)
}

object Foo {
  private[Foo] class Bar(val i: Int) extends AnyVal
  private val bar = new Bar(42)
}

// Exiting paste mode, now interpreting.

defined class Foo
defined object Foo

scala> val f = new Foo
f: Foo = Foo@4a4f9c58

scala> f.foo(null, "", "")
<console>:13: error: type mismatch;
 found   : Null(null)
 required: Foo.Bar
       f.foo(null, "", "")
             ^
+3
source

Something like this might be:

class Foo {
   class Bar private[Foo]()
   private val bar = new Bar
   def foo(x: Bar= bar, a: String, b: String) = println(a + b)
}
+2
source

:

object `(Please use explicitly named arguments)`
def foo(
  `(Please use explicitly named arguments)`:
    `(Please use explicitly named arguments)`.type =
    `(Please use explicitly named arguments)`,
  namedArg1: Int,
  namedArg2: String,
  ...
) = ...
+2

.

, .

$ scala
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.

scala> private val x = new Object ; def f(foo: x.type = x, i: Int) = i
<console>:11: error: private value x escapes its defining scope as part of type x.type
       private val x = new Object ; def f(foo: x.type = x, i: Int) = i
                                                ^

scala> val x = new Object ; def f(foo: x.type = (x: x.type), i: Int) = i
x: Object = java.lang.Object@1e54cb33
f: (foo: x.type, i: Int)Int

scala> f(i = 42)
<console>:13: error: type mismatch;
 found   : Object
 required: x.type
       f(i = 42)
       ^

or not, it looks fine:

    private[this] val x: Object = new java.lang.Object();
    <stable> <accessor> def x: Object = $iw.this.x;
    def f(foo: x.type = $iw.this.x, i: Int): Int = i;
    <synthetic> def f$default$1: x.type = $iw.this.x

or is it a problem of assigning a default value?

but you cannot do this:

scala> val x: x.type = new Object
<console>:36: error: recursive value x needs type
       val x: x.type = new Object
              ^

I think this works because you do not need to say what xis x.type:

scala> object x
defined object x

scala> def f(y: x.type = x, i: Int) = i
f: (y: x.type, i: Int)Int

scala> f(i = 42)
res2: Int = 42

This still allows explicitly providing x, which can be confusing.

I'm too scared to find out why this fails:

scala> object x$$ ; def f(y: x$$.type = x$$, i: Int) = i
defined object x$$
f: (y: .type, i: Int)Int

scala> f(i = 42)
res0: Int = 42

scala> f(x$$, 42)  // or x$$$
<console>:13: error: not found: value x$$
       f(x$$, 42)
         ^

But this suggests that, despite the fact that the object is publicly available, access to it is somehow crippled when changing the name.

+1
source
Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> type `(Please use explicitly named arguments)` = Nothing 
defined type alias $u0028Please$u0020use$u0020explicitly$u0020named$u0020arguments$u0029

scala> def foo(`(Please use explicitly named arguments)`: => `(Please use explicitly named arguments)` = ???, i: Int, j: Int) = i + j 
foo: ((Please use explicitly named arguments): => (Please use explicitly named arguments), i: Int, j: Int)Int

scala> foo(null, 1, 4)
<console>:13: error: type mismatch;
 found   : Null(null)
 required: (Please use explicitly named arguments)
    (which expands to)  Nothing
       foo(null, 1, 4)
           ^

scala> foo(i = 1, j = 4)
res1: Int = 5
0
source

Source: https://habr.com/ru/post/1666042/


All Articles