Support for Groovy style "Power Assertion" in Kotlin?


#1

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


#2

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.


#3

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


#4

@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 (https://github.com/pniederw/expecty).)


#5

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.


#6

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.)


#7

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


#8

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:


#9

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)

#10

you may find this interesting https://github.com/npryce/hamkrest


#11

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


#12

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?


#13

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"

Support Guard Control like swift
#14

HI~ Thanks~