"Expressive vs. permissive languages" and bugs

bearophile bearophileHUGS at lycos.com
Sat Oct 23 17:40:19 PDT 2010


dsimcha:

> At a meta level, I never really understood all these calls for more strictness in
> D to prevent bugs.

Every time I suggest something I try to give a rationale for it, and you are able to shot down my arguments. While if you want a general answer I can't help you much, it's experience from coding & debugging and from reading about how things are done in languages where bugs are much less common compared to C (such languages do exist, as Ada and SPARK and few others).


> 1.  Cases where I intentionally bypass safety features (for example, using manual
> memory management, unsafe casting where the type system is just getting in the
> way, or unchecked shared-memory multithreading) for performance or convenience
> reasons.

In origin, about three years ago, to solve this kind of problems my instinct was pushing toward a solution like the one used by the Cyclone language. Later I have understood why Cyclone has failed (making C safer is hopeless if you also want a handy and terse language) and why the D solution was better (to avoid C solution and use languages features designed to be safer from the start, like D dynamic arrays).

Still, even if Cyclone is a failure, I still think that it's possible to make the C-style code a bit safer (not as safe as Cyclone, but safer than normal C) and keep it almost as handy as before. An example of this effort is the idea of the @tagged attribute for enums. In the end the very good Don has let me understand that was a bad idea, and that enhancement request is now closed, but that @tagged attribute is syntactically clean, you just need it and in theory you don't need to change other parts of the D code.


> In these cases what's really needed is to make existing safe features
> more usable and efficient so I'm not as tempted to bypass them.

This is a good thing, right.


> 2.  High-level/domain-specific logic errors.

In the last months I am developing more and more interest in sofisticated type systems. From what I've seen typestates and Dependent types are able to catch a growing number of those higher level bugs. But D doesn't have that type system (once D has user-defined attributes plus more static introspection it's maybe possible to define linear types with an attribyte like @linear. This idea is quite similar to the uniqueness ideas of Bartoz. But linear types are far simpler, both in implementation and usage, than Dependent types. I have recently shown a post here about dependant types) so this is not a true option. A problem is of course that D must be usable in few years or right now, while maybe it will take too many years to design Dependent types that aren't too much hard to use. They are mostly an interesting research topic still (despite you may use them today in the ATS language), while D is a practical language designed with parts well understood and well known to work now.


> and good contracts/asserts (which D mostly has,

Few months ago in a post I have discussed about some possible improvements of the contract system of D. Introducing the "old" is probably one of the most important missing features. Some older threads about it:
http://www.digitalmars.com/d/archives/digitalmars/D/why_no_old_operator_in_function_postconditions_as_in_Eiffel_54654.html
http://www.digitalmars.com/d/archives/digitalmars/D/Communicating_between_in_and_out_contracts_98252.html

When I have discussed about D contract system improvements, I have said something about "loop invariants" and "loop variants" too. A person has shown me that calling a pure function inside an assert positioned at the top of the loop was probably a good enough loop invariant. So maybe there is no need of explicit syntax for loop invariants in D (despite it's light syntax, it may reuse the invariant{} syntax).

In that post about D contract system improvements I have also said that loop variants aren't that important. In the meantime I have found that instead they may be more important that I have thought, this is one item from a list of ten rules to write higher reliability C code:
http://spinroot.com/p10/rule2.html
The lack of loop variant has caused this famous Zune bug:
http://www.zuneboards.com/forums/zune-news/38143-cause-zune-30-leapyear-problem-isolated.html

If you don't remember what a loop variant is:
http://en.wikipedia.org/wiki/Loop_variant

I have not yet written an enhancement request that lists all the (few) improvements I've suggested for the D contract system. I was lazy.


> though I'd love an alwaysAssert() or
> something that throws an AssertError instead of Exception, like assert(), but
> isn't compiled out in release mode, like enforce(),).

This looks a bit messy.


> One other thing that might
> help here is finer grained control over bounds checking.  I'd love to leave bounds
> checking on for most of a program, but turn it off just for certain
> performance-critical classes/structs/functions.

I think a pragma may be used for this.
But a better solution is of course to introduce a bit more static analysis inside the D compiler, that allows it to remove some bounds checking where it infers the bounds can't be crossed. This is done by the last version of the Oracle Java Machine. On the other hand currently the D language looks designed to don't require a smart back-end, so this may be something to rely on (of course future better D compilers are free to perform such optimization in non-release mode). A disadvantage of those compiler optimizations is that you can't rely on them. While you are able to rely on the performance kick gained from a pragma that locally disables bounds checking :-) Predictability is something I'm appreciating more and more in compilers/languages.

Thank you for your comments.

Bye,
bearophile


More information about the Digitalmars-d mailing list