www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Strict mode

reply bearophile <bearophileHUGS lycos.com> writes:
In some dynamic/scripting languages the basic programming modality is quite
relaxed, this may help the programmer to quickly write a 10 lines long script.
But when they want to write longer programs of 200 or 2000+ lines, some of such
languages offer a "strict mode" that imposes more constraints and helps
avoid/fix bugs.

(Python for example doesn't have a strict mode, it has a single modality,
that's more strict than basic Perl, but less strict than for example Java and
quite less strict than Ada. While for example JavaScript is a mess, its
management of global/local variables is broken.)

The C language isn't very strict. D language is designed to be compatible with
C, and often it just disallows some unsafe things of C.

So "SafeD" modules may also be in strict mode, disallowing some things that are
valid C that can be used in unsafe D modules.

One of the several things that can be mode more strict in D are the retrieval
of variable names in global/local scopes, and class attributes.

For example Ruby forces to prepend class attribute names with  . Most
programmers use some name convention for them, or "this.". Good IDEs give
different colors to class attributes. Replacing programmers conventions with
something standard and compiler-enforced may be positive.

Another possible idea: in strict mode functions must have an annotation that
lists what variables are used from an outer scope, and if they are read,
written or both.

In this example the function "foo" has an input variable "n", returns a tuple
of int and double, and it uses variables "a" and "b" found in an outer scope,
"a" is just read and "b" is read and written (the parentheses around the
multiple output arguments are compulsive, they avoid troubles):

(int,double) foo(in int n) {
    outer in int a;
    outer inout int b;
    
    double tot = 0.0;   
    foreach (i, 0 .. n) {
        b[i] += a[i];
        tot += b[i];
    }
    return (n, tot);
}

Inside this function if you try to a variable "c" found in an outer scope you
have a compilation error. Outer variables have to be listed before their usage.

Using many global/outer variables is bad programming practice that leads to
messy programs (so generally it's probably better to just add to such "foo"
function "a" and "b" among its input/ref arguments), but if you want to use
them, then it's better to list that they come from outside. This helps for
example when you want to translate some strict D code to another language.

There are other ways to make the language more strict, for example disallowing
some automatic casts, etc. (C# already has some of this, for example float =>
double requires a cast. I don't remember if D2 requires this already).

Bye,
bearophile
Sep 24 2009
parent reply language_fan <foo bar.com.invalid> writes:
Thu, 24 Sep 2009 06:17:22 -0400, bearophile thusly wrote:

 There are other ways to make the language more strict, for example
 disallowing some automatic casts, etc. (C# already has some of this, for
 example float => double requires a cast. I don't remember if D2 requires
 this already).

Since your suggestion may add new syntactic constructs, can you somehow show that making the language more strict also improves overall program quality in some ways that unit testing and stronger type system cannot achieve.
Sep 24 2009
parent bearophile <bearophileHUGS lycos.com> writes:
language_fan:

 Since your suggestion may add new syntactic constructs, can you somehow 
 show that making the language more strict also improves overall program 
 quality in some ways that unit testing and stronger type system cannot 
 achieve.

In that example I've shown the possible syntax of tuples, but that's a feature unrelated to strictness. So the only syntax I have suggested related to strictness is that "outer" keyword followed by the list of names that aren't arguments (with in/out/inout too). There are several D features that can be removed and replaced by unit testing. Sometimes they are two ways to do the same thing, to specify semantics and restrict behaviours. The advantage of unit tests is that they are more flexible and allow to test more complex things. The advantage of various annotations is that they are usually shorter to write, they are more compiler-enforced and they can be more systematic. In my D programs I like to have both. In my D code for every 1 line of code I write about 2.5 lines of unit tests, about as in Python (where I don't add type annotations and accessibility annotations). You can create a stronger type system, but you often have to give it more inputs. Otherwise you need complex automatic inference systems that increase compiler complexity a lot and compilation time too. So that "outer" can be seen as an annotation. It's not easy to be sure "outer" improves code quality/readability. My experience in trying to translate and understand code written by other people tells me that global/outer variables make such translation/understanding quite harder. Having a language where such outer names must be listed looks like a compromise between a language like C/D with no limits in where it looks for names, and a language like Delight (a D resyntaxed, but with other differences and improvements) that forbids global/outer mutables at all. Such "outer" can be useful if you translate some D code to other languages, because good software often gets translated. It's good to help future programmers to abandon their D programs and translate them to other languages :-) Bye, bearophile
Sep 24 2009