Calling a function without parameters in infix notation


#1

I assume my title describes what I am up to but, to be honest, I am not sure. First of all: this is not a serious project, just playing around to get to know scala.

object Helpers
{
  class AtOperation(list: List[Int])
  {
    def at(index: Int): List[Int] = list match {
      case first :: rest =>
        val (before, after) = rest.splitAt(index-1)
        before ++ List(first) ++ after
    }
  }

  class MyInt(value: Int)
  {
    def into(list: List[Int]) = new AtOperation(value :: list)
  }

  class Hey
  {
    def insert(value: Int): MyInt = new MyInt(value)
  }

}

import Helpers._

object Test2 extends App
{
  println(new Hey insert 42 into List(1, 1, 1, 1) at 3) // prints List(1, 1, 42, 1, 1)
}

This works fine. But what I actually want to write is:

insert 42 into List(1, 1, 1, 1) at position 3

So, no new Hey in the beginning and there should be a position after at. Is that possible?
My current attempt is:

object Helpers
{
  class PositionOperation(list: List[Int])
  {
    def position(index: Int): List[Int] = list match {
      case first :: rest =>
        val (before, after) = rest.splitAt(index-1)
        before ++ List(first) ++ after
    }
  }

  class AtOperation(list: List[Int])
  {
    def at = new PositionOperation(list)
  }

  class MyInt(value: Int)
  {
    def into(list: List[Int]) = new AtOperation(value :: list)
  }

  class Hey
  {
    def insert(value: Int): MyInt = new MyInt(value)
  }

}

import Helpers._

object Test2 extends App
{
  def insert(value: Int) = new MyInt(value)


  println(insert(42).into(List(1, 1, 1, 1)).at.position(3)) // this works fine
  println(new Hey insert 42 into List(1, 1, 1, 1) at position 3) // position is interpreted as a parameter of at :-(
}

This is apparently not working as expected :frowning:


#2

Parsing precedes type checking. a b c is always parsed as a.b(c), regardless of what types are involved.

Note also that the syntax where a b is parsed as a.b (if there is nothing following) is on its way out of the language. For some years now, using this syntax has produced a warning, which perhaps you didn’t notice. In Scala 2.13 it will be an error unless you explicitly enable the syntax, and the syntax will likely be removed entirely from some subsequent Scala version, because it interacts poorly with semicolon inference.

In general, using the infix and postfix syntaxes to do English-y things like this is something that many experimented with in past years; as a community, I think we now collectively mostly agree that these were failed experiments that resulted in code that was hard to read (except superficially) and hard to write.


#3

I hope that does not mean we will lose operator infix notation, such as

val c = a + b // where a and b are user-defined types


#4

Nope, the only problematic variant are postfix operators, i.e. val c = a b where b is the operator. An example for why postfix is problematic can be found in the docs.

Postfix operators are already behind a feature flag (import scala.language.postfixOps), I don’t think there are any plans to remove or reduce infix operators.


#5

I recently answered a similar question on StackOverflow: https://stackoverflow.com/questions/51965278/scala-dsl-invocation-that-mimics-english/51970294#51970294

But this is mostly a fun exercise. Not something I would recommend actually doing.