Support for Groovy style "Power Assertion" in Kotlin?

I wonder if Kotlin might now or in the future have the language support to be able to do something like the handy "power assertion" feature as seen in Groovy.

Groovy’s “Power Assert”

Example:

a = 10
b = 9
assert 91 == a * b

//produces…

Exception thrown
Assertion failed:
assert 91 == a * b
          |  | | |
          |  10| 9
          |   90
          false

4 Likes

This really is a nice feature of Groovy! But I suppose being that concise would only be possible with access to the syntax tree. I don't see any way for a custom assert statement to get a hold of the original expression 91 == a * b. An alternative would be a assert keyword with those capabilites that is part of the Kotlin language.

Or we could do some hard-core magic, but anyways it's hard to provide anything like that as a user-defined library.

1 Like

@abreslav Would you, in principle, accept a contribution of this feature, assuming it is well done? No promises yet, but I miss this feature every day, and have some experience with designing/implementing it. (I’m the original author of power asserts for Spock, Groovy, and Scala (GitHub - pniederw/expecty: Power assertions (as known from Groovy and Spock) for the Scala language.).)

8 Likes

My dream is for assert to not be a mere debugging mechanism that doesn’t work in production, but to be an elegant way to check conditionals.

assert param > 0 : IllegalArgumentException("My message")

or even (just like the guard statement in Swift)

assert (param is String) else {
      ... do stuff ...
}

// param has been smart cast to String
print (param.length)

Of course, this is still compatible with “power assertions” to give a friendlier message in an AssertionError when no else is specified.

1 Like

Which assert doesn’t work in production? Are you saying you want an assert that’s always enabled, and doesn’t require runtime assertions to be turned on for the JVM? (Currently, the assertion functions in kotlin.test fit that bill, and I can’t think of a reason not to use them in production code.)

1 Like

It’s two things. The first, yes, is to be always-enabled. The second, is to throw meaningful exceptions.

If all he wants is something similar, doesn’t this fit the bill without too much magic?

infix fun <T> T.assert(test: T): T = if (this != test) throw AssertionError() else this

fun Boolean.assert() = this assert true

Example usage:

val a = 10
val b = 9

91 assert a * b
a * b assert 91

(91 == a * b).assert()

Can also be used as an expression since <T> assert(T) returns itself.

val fifty = 10 * 5 assert 50

Enjoy and hope it helps :grinning:

Nice suggestion. I will try to make something that gives you a similar feature to Swift’s guards.

EDIT: Would this suite your needs?

inline fun assert(predicate: () -> Boolean) = assert(predicate())

infix fun assert(result: Boolean) = Guard(result)

class Guard(val result: Boolean) {

	infix fun or(exception: Exception) {
		if (result)
			throw exception
	}

	infix fun or(body: () -> Any) {
		if (result)
			body()
	}

}

Example usage:

assert (param > 0) or IllegalArgumentException("My message")

And:

assert (param is String) or {
    ... do stuff ...
}

// unfortunately Kotlin doesn't do smart cast here (because it would slow compilation)
1 Like

you may find this interesting GitHub - npryce/hamkrest: Hamcrest for Kotlin

That’s pretty good. Would it be possible to throw AssertionError when no or is specified? Or at least a compile-time error?

sometimes we have define the option type such as “var a: ClassA? = null” ,and then i need check a :
val realA = a?:return
if(realA.somePr == true){
//do …
}
//…
.but i want to use it like swift :
guard let realA = a else {
return
}
if(realA.somePr == true){
//do …
}
//…
how to impl it?

Does this seem like it could work for you?

inline infix fun <T> T.or(orBlock: () -> T) = if (this == null) orBlock() else this

Here’s an example:

val a: String? = null
val realA = a or {
    "b" // imagine we actually did work instead
}
println(realA) // prints out "b"

HI~ Thanks~

@pniederw1 have you seen the kotlin compiler plugin architecture? Saw a talk about this at KotlinConf 2018 and the first thing that came to mind was “OMG this could make Spock stuff possible” (big fan :D)

This was the talk:

I was just starting to look into the feasibility of it, poking around thinking of power assertions and parameterised tests, since I miss those greatly. I see this was a while back, so wondering if you are still considering something towards this?

The best thing I saw until now was this plugin:

The only limitation is that it only works with expressions evaluated to booleans. Fluent assertions don’t seem to work yet.

2 Likes