Ensuring does not accept partial function

I’m trying to debug a program, and I’m attaching ensuring to several methods to check the post conditions

I see that something like the following fails, surprisingly. Inkeeping with scala conventions it ought to be accepted.

  def project(loc: Location): UnitSqCoord = {
        require(-90 <= loc.lat && loc.lat <= 90, s"loc=$loc failed -90 <= ${loc.lat} <= 90")
    require(-180 <= loc.lon && loc.lon <= 180, s"loc=$loc failed -180 <= ${loc.lon} <= 180")
    UnitSqCoord((loc.lon + 180.0) / 360,
                (1.0 + sin(toRadians(loc.lat))) / 2)
  } ensuring{ case UnitSqCoord(x,y) => 0 <= x && x <= 1 && 0 <= y && y <= 1 }

However, the following works, but is more wordy.

  def project(loc: Location): UnitSqCoord = {
        require(-90 <= loc.lat && loc.lat <= 90, s"loc=$loc failed -90 <= ${loc.lat} <= 90")
    require(-180 <= loc.lon && loc.lon <= 180, s"loc=$loc failed -180 <= ${loc.lon} <= 180")
    UnitSqCoord((loc.lon + 180.0) / 360,
                (1.0 + sin(toRadians(loc.lat))) / 2)
  } ensuring{xy => xy match {case UnitSqCoord(x,y) => 0 <= x && x <= 1 && 0 <= y && y <= 1 }}
1 Like

How is it failing? I can’t test your exact code cause it’s not self-contained, but when I try to mimic it everything just seems to work as expected.

When I use ensuring { case something => some_boolean} the compiler tells me

Error:(132, 14) missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
  } ensuring {

But when I use ensuring{ x => x match {case something => some_boolean} it compiles and works as expected.

Aha when I switch to 2.12 I get the same error. I can’t really explain it, but whatever the cause is seems to be fixed in 2.13.

The weirdest thing is that ensuring { case x => y } should be syntactic sugar for ensuring {_ match { case x => y }}. So it’s unexpected that one works and the other doesn’t.

2 Likes

Wouldn’t it be better to ensure that a UnitSqCoord cannot be created unless the conditions are met? I.e.,

case class UnitSqCoord(x: Int, y: Int) {
  require(0 <= x && x <= 1, "x-coordinate must be between 0 and 1")
  require(0 <= y && y <= 1, "y-coordinate must be between 0 and 1")
}

yes, I had done both. It’s only for debugging, as ensuring and requiring do not switch off automatically in deployed code. It is unfortunate that require and ensuring don’t disable themselves in non-debug mode, the programmer is forced to edit his code, risking introduction of new bugs.

Hmm. I’m not certain about ensure, but I’m fairly sure that require is supposed to go away in production-mode code, same as assert. But you do need to make sure that you’re telling the compiler to do so. Quoting the docs:

A set of assert functions are provided for use as a way to document and dynamically check invariants in code. Invocations of assert can be elided at compile time by providing the command line option -Xdisable-assertions , which raises -Xelide-below above elidable.ASSERTION , to the scalac command.

I think require is not elidable but ensuring is.

require can’t be turned off in production, but assume and assert can, see Quick tip: use assertions liberally