#2589 Assert support

fraya Thu 12 Jan 2017

Why don't support an assert function?

It was asked before ( fantom.org/forum/topic/1389 ), but Test#verify is not a substitute because your class must inherit from Test.

Mr Philip Guo says it better ( http://www.pgbovine.net/programming-with-asserts.htm ).

Java removed assert from C language in the beginning and added it in Java 1.4.

SlimerDude Thu 12 Jan 2017

The main usage for asserts is for validating method inputs at runtime. This could easily be achieved with a simple mixin:

mixin Assert {
    Void assert(Bool condition, Str msg := "Assert failed") {
    	if (!condition) throw ArgErr(msg)
    }
}

// use it like this

class Example : Assert {
    Float squareRoot(Float num) {
        assert(num > 0, "Can not calculate square roots of negative numbers")
        ...
    }
}

Note that one of the main uses of asserts in Java was to check for nulls, which Fantom neatly side-steps with nullable types.

Personally I see assertions as a nice idea, but I don't see how they are more useful than basic arg checks. And I don't really see their usage to be prolific enough to warrant their own keyword or inclusion in the core API.

fraya Fri 13 Jan 2017

Thank you, SlimerDude:

You are right, assertions can be mainly used for validate inputs but there are more reasons to use them, see 1 in references. I think is more useful than basic arg check because the code is shorter and factors in one method this checks.

In the fantom source there are ~ 272 times where throw ArgErr is used. Probably is not enough for a keyword, but what about an assert method in Obj ?

I made an Assert like pod, but with only a mixin looks like a mini-pod :)

Please take my questions with patience because I'm a student and I don't know enough about Fantom.

References:

  1. http://stackoverflow.com/questions/13218496/what-is-the-use-of-assert-in-java
  2. https://golang.org/doc/faq#assertions, golang against assertions

SlimerDude Fri 13 Jan 2017

Hey Fraya,

Your opinion is just as valid as anybody elses and the question of Asserts is a good one to ask. As the GoLang link states, it is a contentious issue.

I myself lean towards the opinion of GoLang in that decent, targeted exception throwing and handling is the way forward.

Assert how often?

In my early days, I did try asserting every input argument of every method (and some return values) but quickly found it to be tedious and anti-agile (in the strictest sense). For when it came to refactoring, it then takes a long time to re-state the asserts.

While I do believe that input arguments and other conditions should be checked on some method invocations I don't believe it is useful to do it on every method.

Assert what?

This answer on StackOverflow talks about using assertions to enforce Design-by-Contract - again, a good idea, but contract of what?

This is analogous to Unit Testing, which I believe is mis-interpreted by most programmers today to mean Method or Class Testing. No, a single class should not blindly be designated a unit. Sometimes it is, but not always.

So while assertions are good, what (I would say) is more valuable is what you assert and when. Software design. And if these assertions are then so important for the contract you designed, they should be tested. Which is what I created Fancordion for, higher level acceptance testing.

The other contentious issue around assertions in Java, is that they're typically turned off in production?!? If your assertions are so important as to require testing, why would you turn them off!?

What to throw?

As mentioned earlier, assertions shouldn't just check input arguments, they should check the validity of all data the method relies on - including fields and other class data. Which means your assert() method shouldn't really throw an ArgErr because it will not always be an argument in error.

So perhaps a generic AssertErr would be more fitting? But an issue I see with that is that it is generic and not fit for purpose for all circumstances.

Errs (and Exceptions) should always strive to provide as much context around the error as possible. That is why IocErr, NotFoundErr, and EfanErr all contain extra fields and augment the toStr() method; which isn't possible with one generic AssertErr class.

So if there's no generic AssertErr class, there can not be a generic assert() method, and now we're back to if statements throwing contextual Errs.

It's not all bad

But after saying all that, I don't dislike assertions. I'm just saying they're not my cup of tea, and I probably wouldn't use them (much) if they existed. But hey, I don't use Fantom DSLs either! But if others love them, knock yourselves out!

So, assuming assertions were to be implemented, my first ideas was to have an Assert class in the util pod - as I'm still not sure the concept is core enough.

But then again, assert is already a Fantom keyword (presumably because of Java) so why not put it to use!?

fraya Sat 14 Jan 2017

QED :)

Thank you for an interesting and well written response. I've learnt a lot.

Login or Signup to reply.