Re: [Vala] non-null broken in vala 0.9.3



Hi all,

I'll answer a few things that came up in the discussion:

Why do I think that enforcing nullchecking by assignment 'non-null =
(!)nullable' is good, and enforcing checking when accessing members
is bad? Well: the first one is a contract programming technique, the
second is not.  

I disagree.  I think one of the most basic contracts is that an object
is non-null when you access its members.  Its an implicit contract that
is very important.

But there's a difference between having obtained a reference to some
external object (that means transfer of data, and that means a need to
validate obtained data, and that means having a nullcheck), and having
a reference to object that is being used in the current scope. The
latter situation means that we're managing object's internal state
(let's count object existence or being null as it's internal state), so
if this state is wrong, it does not mean "whoops, I've accidentally a
whole object! let's give some checking here then!", it means rather
that the algorithm has bugs. And I don't think that contracts should be
used to maintain algorithm flow, they're for data validation only.

What is more, calling methods on objects is not something that I'd call
data transfer. On a low, technical level it's indeed passing a pointer
to other function, but when we're considering it on the level of
object-oriented programming, it's just using an object. Just like using
a number when we perform floating-point division. Whether the used
object is valid or not should be not checked, or checked at run-time;
the example can be division by zero. It's quite uncommon to check if
divisor != 0, but if it is zero at run time, SIGFPE will be raised (and
most probably - ignored). Therefore I suggest treating objects the same
way - when there's no object transfer between different scopes /
modules, don't contract.

I think the idea behind a language with non-null types is to use
algorithms that never need a null value except to handle inputs and
outputs.  IMO, if you have a nullable variable, you have a design
problem.

And:

If what you mean would look like this:

Foo? a = bar();
// a is unsafe and can't be accessed
if (null != a)
{
// a is safe to use in this block
}

then I don't really see how that is any different than what we have now:

Foo? a = bar();
// a is unsafe and can't be accessed
if (null != a)
{
Foo b = (!)a;
// b is now safe to use
}

It's not true. If I'm using lots of functions, that return nullables,
doing 'if(foo != null) non_null_bar = (!) foo;' will be disrupting:
- it's too verbose, obfuscates code and makes programmer considering
  porting his code to javascript
- it's increases memory and decreases performance, because now there
  are two references per object, and they probably won't be optimized
  out by gcc (because we call unref() on both of them when leaving
  function).

The question if returning null to indicate not completing operation is
a "right way", or the exceptions would be better indicator of such
situation, is a good topic to have a little flame war, but as far as
such flame wars occur sometimes and take casualties, I think that vala
should enable both these techniques. And as for now, using experimental
non-null makes "return null on failure" extremely unfriendly technique.

For the rest of them,
you'll just have one extra assert(), which is not a problem but rather a
good practice. 

Isn't the point of having non-nullable types to eliminate runtime checks?  When
testing your program, its very easy to miss cases that would lead to the
assertion failing, which is still a bug.

It's true, and it's also true that experimental non-null at this moment
is a perfect compile-time checking utility (as far as frustrated
users won't start putting (!) everywhere to silence "these stupid
errors"). And a very unfriendly utility too.

In my opinion, current usage of (!) operator is contrary to all purpose
of experimental non-null feature. Currently we use this operator to
indicate "this assignment is safe!", and IMO this should be "this
assignment is dangerous, but I take it anyway". The typical current use
case:

SomeType? foo = bar();
if(foo == null) return; //dear compiler, I want to check if foo is not
null...
baz((!)foo); //sweetheart, we both know that the exclamation mark means
that passing foo to baz() is perfectly safe!
foo2 = (!)foo;//and here too, because you my darling are sweet blondie
who never understands what I'm talking about if I don't repeat it.

But sometimes it looks like this:

SomeType foo = (!) bar(baz);
/* Dear compiler, I suppose that bar() will never return null here,
because I know that baz is here constrained is such way, that it will
never make bar() produce null.
Yes my darling, I know what I'm doing, as I wrote above, the
exclamation mark means that this assignment is perfectly safe!
Believe me! I'm not putting nullcheck here, because bar() is a
one-liner, probably will be inlined, and I'm using lots of similar
functions in my whole program. Checking everytime would make it run
much slower */

And all the idea behind compile-time checking is now worthless.

In the ideal world it would look like this:

SomeType? foo = bar();
if(foo == null) return; //dear compiler, I want to check if foo is not
null...
baz(foo); //now my smart little beast we both know that this place
wouldn't be reached if foo were null, so passing foo here is safe, and
therefore I'm not putting (!), and there will be no error nor warning.

And:

SomeType foo = (!) bar(baz);
/* Dear compiler, I know that static code analysis would reveal, that
bar will never return null here. But you seem to not know about it.
Therefore I put here an exclamation mark, and exclamation mark always
brings to my mind screaming, fear and danger. Therefore please accept
this exclamation mark as a proof that I'm aware of writing dangerous
code and of course I know that you'll issue compiler warning in every
place, where i put these operators. (!)*/

Well. That's all for today. BTW, don't you know why I did not receive
mail with my original post yesterday? I have set receiving my own mail
too, but it did not reach me...

best regards,
AW.

-- 
Mój klucz publiczny o identyfikatorze 1024D/E12C5A4C znajduje się na
serwerze hkp://keys.gnupg.net

My public key with signature 1024D/E12C5A4C is on the server
hkp://keys.gnupg.net

Attachment: signature.asc
Description: PGP signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]