No by-name parameter type allowed here

I was surprised with this compiler error message.
Is this a real limitation, or is it simply a question of using the correct syntax?

no by-name parameter type allowed here

The error message appears at the function definition site, not the function call-site.
I have a function defined like this.

  def findSimplifier(simplifiers:List[(=> Type)]):Type = {
    simplifiers match {
      case Nil => this
      case s::ss =>
        val t2 = s
        if ( this == t2)
          findSimplifier(ss)
        else
          t2
    }
  }

And the call-site looks like this:

  override def canonicalizeOnce: Type = {
    findSimplifier(List[(=> Type)](
    {
      if (U.contains(EmptyType))
        EmptyType
      else
        this
    },
    {
      IntersectionType.apply(U.distinct)
    }
))
}

It’s a limitation. Not in the sense of technical limitation, but a conscious design decision. Only a parameter can be by-name, not the element of a list.

But what you’re probably looking for is List[() => Type].

I had to change all the call sites from

List({...},
     {...}, 
     {...},
     ...)

to

List(() => {...},
     () => {...}, 
     () => {...},
     ...)

and it works. I was just surprised by the limitation. It is surprising when things don’t compose logically.

By-name parameters are great but are too simplistic. If you need more lazyness in your code you can consider using Eval from cats. (as I just mentioned in other thread)

It is now 2.5 years later, and I am again hit by this inconsistency. Again I’m surprised when things con’t compose logically.

no by-name parameter type allowed here
  def rteIfThenElse[E](seq: Seq[(Rte, => E)], otherwise: => E): Seq[Any] => E = {

Here is how I’d like my call-site to look:

object sanityTest {
  def main(argv: Array[String]): Unit = {
    import rte.RteImplicits._
    import scala.language.implicitConversions
    import rte.Rte.rteIfThenElse
    val int = classOf[Int]
    val str = classOf[String]
    val f = rteIfThenElse[Int](Seq(
      Star(int) -> {
        println("case 1")
        1
      },
      Star(str) -> {
        println("case 2")
        2
      },
      Cat(Star(int), Star(str)) -> {
        println("case 3")
        3
      }),
      {
        println("default case")
        4
      })
    f(List(1,2,3,4,5))
    f(List("one","two","three", "four"))
    f(List("one","two",3, 4))
    f(List(1,2,"three","four"))
  }
}

I suppose that changing xxx -> { ...} to xxx -> () => {...} would not be so bad. Curious limitation. But it turns out xxx -> () => {...} is not allowed, I also need an additional set of parens xxx -> (() => {...}), to avoid the following error.

not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
      Either create a single parameter accepting the Tuple1,
      or consider a pattern matching anonymous function: `{ case (param1, param1) => ... }
      Star(int) -> () => {

I’m somewhat curious to know whether the Eval type in cats alleviates this syntactically ugliness.

Yes, Eval would work there, rather than () => { ... } you would do Eval.later { ... } (or always depending on your use case); btw, technically speaking, if you are going to have things like println then you should use IO rather than Eval but whatever.
Whether or not you find that to be more readable is up to your personal preference.

The intent is to figure out what the most Scala-friendly way would be to express some things that are idiomatic in lisp such as the following.

(defun detect-pattern (seq)
  (rte-case seq
    ((:* integer)        (do-something 1)  "all integers")
    ((:* number)         (do-something 2)   "all numbers")
    ((:cat string (:* t)) (...) "begins with string")
    ((:* t)               (...) (...) (...) "other")))

The idea is to have a piece of code which behaves somewhat like and if then else then else then else … where only one of the alternatives evaluates. As I understand, this is exactly the intent of call-by-name. But as you said, Scala’s support for call-by-name is pretty simplistic and as we see does not generalise in a way which makes it useful for anything beyond simplistic cases.

The code in Common Lisp is a call to a macro, but since Scala’s support for macros is dubious, I decided to implement it as a normal function.
The Scala function rteIfThenElse returns a function that can then be called with the argument corresponding to the one that I pass in-line to the lisp macro as seq.

Scala 2 support for macros is dubious. The pattern you’re showing here looks like it would probably be fairly easy to build in the much-better-supported Scala 3 metaprogramming. (In particular, my guess is that a recursive type match would look kind of like this.)

Worth mentioning varargs can be call-by-name in Scala 3, but (again) evaluation is not flexible (all or nothing).

object X {
  def f(ns: Int*)(ss: => String*) =
    val i = ns.indexWhere(_ >= 42)
    if i >= 0 then ss(i) else "empty"
}

object Test extends App:
  def intOf(x: Int): String =
    println(s"eval $x")
    x.toString
  println {
    X.f(17, 42, 37)(intOf(17), intOf(42), intOf(37))
  }
  println {
    X.f(17, 27, 37)(intOf(17), intOf(27), intOf(37))
  }

Also using context functions,

trait T

object X {
  given T = new T {}
  def f(ns: Int*)(ss: T ?=> String*) =
    val i = ns.indexWhere(_ >= 42)
    if i >= 0 then ss(i) else "empty"
  def g(ps: (Int, T ?=> String)*) =
    val i = ps.indexWhere(_._1 >= 42)
    if i >= 0 then ps(i)._2 else "empty"
}

object Test extends App:
  def intOf(x: Int): String =
    println(s"eval $x")
    x.toString
  println {
    X.f(17, 42, 37)(intOf(17), intOf(42), intOf(37))
  }
  println {
    X.f(17, 27, 37)(intOf(17), intOf(27), intOf(37))
  }
  println {
    X.g(List(17, 42, 37).map(i => (i, intOf(i)))*)
  }

with desired semantics

eval 42
42
empty
eval 42
42

what is ?=> ?

Question about exposing IO and Eval. Is it a good idea to expose IO or Eval in the api of my library function? It seems to me an API which requires the caller to use anonymous functions or call-by-name call-site arguments is more reasonable than requiring the caller to explicitly invoke a cats object of some sort.

For me, it seems cleaner, to not expect the user of my API to understand its implementation; he needs to understand how to call it, and its black-box behavior. If he has questions about its implementation, he can look into the code. Right?

It is disappointing to find things in Scala which do not compose well. When I started learning the language, one of there promises that I liked what that concepts are composable. e.g., I can use functions within functions, classes within classes, objects in objects. However, one hits a wall.

Here’s an example. I can define multiple functions named f in the object Foo, but I cannot do that inside the function g.

object Foo {
  def f(a: String, b: String): Int = 1 // this works

  def f(a: Int, b: Int): Int = 2 // this works
  
  def g():Int = {
    def h(a: String, b: String): Int = 3 // this fails to compile

    def h(a: Int, b: Int): Int = 4 // this fails to compile

    h("hello","world") + h(1,2)
  }

  def main(argv:Array[String]):Unit= {
    println(f("hello","world") + f(1,2) + g())
  }
}

Here is the error

method h is defined twice;
the conflicting method h was defined at line 7:9
def h(a: Int, b: Int): Int = 2

T ?=> String defines a context function (introduced in Scala 3). Basically it’s a function type, where the parameter list is givens (or implicits in Scala 2 terms). So in the above example the functions in ss take a given T as parameter, which is provided by the line above, so at the callsite

X.f(17, 42, 37)(intOf(17), intOf(42), intOf(37))

the intOf calls are actually each inside a function, which only takes given parameters that are filled at compile time, so the parameter list isn’t required to be written out.

So in this case the parameter is solely used to save writing the () => {...} part.

In general I agree with this, in case of libraries like cats I’d say it depends on how your library will be used. If you want to provide a purely functional API and your library does some kind of I/O, there is no way around some specialized type for wrapping side effects, be it returning an IO monad or requiring a typeclass on a parameter to let the user select the IO wrapping type.

If you aren’t writing in purely functional style and don’t expect your users to, I’d say keeping library types out of public API is a good guideline.

1 Like

It has always been a bit confusing to me in which case a function is partially evaluated, or implicitly evaluated. We had/have the problem in Scala 2 that sometimes f calls the functionf with nor arguments, and sometimes f represents the function itself. As I understand, this ambiguity has been fixed in Scala 3.
But there’s also the issue of functions with multiple parameter lists. I can call the function like this f(1)(2), or I can call it like this f(1). If the 2nd argument is implicit then f(1) is compiled (if I understand correctly) as a call with both arguments provided. but if the argument is not implicit, then g = f(1) is a partially evaluated version of f which can later be called as g(2).

Maybe my understanding is completely wrong here.

That looks correct, functions with multiple parameter lists, if given only some of their lists at call site, evaluate to a function with the remaining parameter lists.

Yes, in Scala 3 f(1)(2) is always calling a function f that has two regular parameter lists and in that case f(1) would return a function. A list of given parameters has to be marked at the call site if provided explixcitly:

// no given parameters: function evaluates list by list
def f(a: Int)(b: Int) = a + b

val x: Int = f(1)(2)           // == 3
val partial: Int => Int = f(1) // == (b: Int) => 1 + b

// using marks parameters that have to be in given scope:
// always filled by compiler, marked if explicitly passed at call site
// never returns a function from not providing that parameter list
def g(a: Int)(using b: Int) = a + b

given Int = 2
val y: Int = g(1)          // == 3; compile error if no given int in scope
val z: Int = g(1)(using 2) // == 3; passing explicitly requires `using` at call site too

So the behavior didn’t really change, but in Scala 2 you couldn’t infer what happens if you leave of a parameter list from reading only a call site.

1 Like

Note I am not suggesting using IO in your case, your code is pretty far away of when it would be useful.

About Eval, I personally don’t think it is bad to show that in a public API, cats is a pretty well-known library, many people would already have it in the classpath and if you are already using it then it makes sense to let your users access it.

However, another solution to your problem is to add a simple factory of functions like this:

// Pick whatever name you find is best
def run[A](block: => A): () => A = () => block

Which you then can use like this:

Cat(Star(int), Star(str)) -> run {
  println("case 3")
  3
}

Rereading the thread, I’m also curious about your use case there. Is your goal to create the list of conditions dynamically? Because otherwise the idiomatic solution in Scala would be to simply use an “if-elsif-else” chain or a pattern match. If you make your Star and Cat into extractor objects the syntax would even look pretty similar, something like:

val f: Seq[Any] => Int = seq => seq match {
  case Star(int) => {
    println("case 1")
    1
  }
  case Star(str) => {
    println("case 2")
    2
  }
    //...
  case _ => /*default case*/
}

I don’t disagree, though I don’t know how much of it is due to historical understanding of OOP.

Local functions vs members is a huge stumbling block in the REPL, because it suddenly matters whether two definitions of f are overloaded members of a class.

People have always asked for the ability to import various symbols with the same simple name and have overloading resolution select between them, rather than picking one binding of the name. I think the discussion around importing extension methods has turned in this direction.

OOP vs FP is whether the locus of composition is the class or the function.