Ensuring with tuples


#1

Simple one please (ignoring fact it can be simplified to just ensuring { ._1 != 1 }:

def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { _._1 != 1 && _._2 != 11 }

I think this doesn’t work because ensuring is expecting a type of type Any so you have to do a case match on the variables but then you end up naming the constituents of the tuple which I don’t need to?

I get confused because sometimes underscores refer to consecutive parameters so they refer to different items - is this what is going wrong here?


#2

ensuring expects a function A => Boolean, where A is the type of the previous expression. So, in your case it expects (Int, Int) => Boolean, which is what you want.

The reason your code does not work is that you are trying to have two different underscores refer to the same argument (also, underscore notation only works with “simple” expressions, and I’m not sure yours is simple enough).

This works:

def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { tup => tup._1 != 1 && tup._2 != 11 }


#3

Tab completion shows alternatives:

scala 2.13.0-M4> def ab(n: Int): (Int, Int) = { (n, n+10) }.ensuring
                                                                      
def ensuring(cond: ((Int, Int)) => Boolean,msg: => Any): (Int, Int)   
def ensuring(cond: Boolean,msg: => Any): (Int, Int)                   
def ensuring(cond: Boolean): (Int, Int)                               
def ensuring(cond: ((Int, Int)) => Boolean): (Int, Int) 

A usual idiom is to match because it’s easy to read.

def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { case (x,y) => x != 1 && y != 11 }

I have a mental block about p._1 syntax. Since you bring it up, it would be extraordinary if this worked:

ensuring(pair => pair._ != 1 && pair._ != 11)

That is, each underscore requests the next element of the product from which it is selecting.


#4

Thanks for both responses. It now works using curoli’s method.

Regarding the case statement, I get the following:

scala> def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { case (x,y) => x != 1 && y != 11 }
<console>:11: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
   def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { case (x,y) => x != 1 && y != 11 }
                                                       ^

Trying to use one of the workarounds from https://github.com/ReactiveX/RxScala/issues/160 doesn’t help…

scala> def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { _ => match {case (x,y) => x != 1 && y != 11 }}
<console>:1: error: illegal start of statement
   def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { _ => match {case (x,y) => x != 1 && y != 11 }}

#5

That’s because you didn’t emply the workaround correctly. It should be:

scala> def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { _ match { case t => t._1 != 1 && t._2 != 11 } }
ab: (n: Int)(Int, Int)

#6

Sorry about that. There was a PR to help inference.

snips $ scalam
[info] started at Thu Aug 30 14:47:53 PDT 2018
Welcome to Scala 2.13.0-M4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.

scala 2.13.0-M4> def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { case (x,y) => x != 1 && y != 11 }
ab: (n: Int)(Int, Int)

scala 2.13.0-M4> :quit
snips $ scala -Dscala.repl.info
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.
[info] started at Thu Aug 30 14:48:09 PDT 2018

scala 2.12.6> def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { case (x,y) => x != 1 && y != 11 }
<console>:11: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
              def ab(n: Int): (Int, Int) = { (n, n+10) } ensuring { case (x,y) => x != 1 && y != 11 }
                                                                  ^

scala 2.12.6> :quit