www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - strict

reply bearophile <bearophileHUGS lycos.com> writes:
Pure functions are nice because a smart compiler can sometimes perform some
optimizations with them that aren't possible with normal functions. But for me
their main advantage is that they help avoid some bugs, because they can't
modify global state nor change their behaviour on its base (we can ignore
memory overflow, and maybe even exceptions). My Python/Delphi programs that are
mostly composed of nearly-pure functions are often the ones with the lower bug
count.

I have seen that's true in OOP too: methods that are static (and don't use
static attributes, they are pure methods, essentially) are often the less buggy
ones. So I use static methods where I can, every time I can write a method that
uses just the input arguments.

But programming in D with just pure functions is not always handy, and in OOP I
sometimes must alter instance attributes, so they can't be pure. And sometimes
using a variable that's not an argument of the function produces a little
faster code/function.

So in D I can think of something intermediate between a pure function and a
normal function/method, something that keeps code flexible but with a lower bug
count. For this I can think about an attribute  strict that can be used on a
free function, a nested function, an object method, and even a class (it means
all it methods are  strict). Even  strict modules are possible (it means all
callables inside it are  strict). (If I will ever design a new imperative
language this will be the default behaviour. Using outer names randomly as in
C/Java/C#/D is bad. Python3 partially avoids this trap with its "outer" and
"nonlocal" statements).

 strict denotes a normal function/method, where all the names (variable) it
uses inside are written down in an explicit way. Some of such names are normal
function arguments, the other names can be global variables, variables from an
outer function, instance attributes, static class attributes, enums.

// inside here types are optional
 strict(in int y, in z, out k, inout w) int foo(int x) {
  // ... code
}

This function/method "foo" takes int "x" as argument. Foo can't use
outer/instance/static names beside "y","z","w","k" ("y" and "z" can't be
written inside foo, "k" can't be read inside foo, and "w" is read/write by foo).

Some alternative syntaxes, a better syntax can be invented:

 strict_in(int y, z)
 strict_out(k)
 strict_inout(w)
int foo(int x) {
  // ... code
}


 strict int foo(int x) {
   in int y;
   in z; // types are optional
   out k;
   inout w;
  // ... code
}


 strict [in int y, in z, out k, inout w]
int foo(int x) {
  // ... code
}


 in int y;
 in z;
 out k;
 inout w;
 strict int foo(int x) {
  // ... code
}


 strict int foo(int x) {
   strict_in int y;
   strictl_in z;
   strict_out k;
   strict_inout w;
  // ... code
}


 strict int foo(int x) {
   nonlocal_in int y
   nonlocal_in z
   nonlocal_out k
   nonlocal_inout w
  // ... code
}


Why it's useful: system theory says that improving the separation of subsystems
you reduce unwanted side effects, improving the reliability of the whole system.

That's why D modules too must produce a better isolation: as in Python "import
bar;" has to import only the "bar" name in the namespace, so for example there
are no new global variables and no surprises. This is a small change to the D
module system that will improve D code. A simple syntax like "import foo: *;"
can be used for the current (to be discouraged) behaviour.

Bye,
bearophile
Feb 14 2010
parent BCS <none anon.com> writes:
Hello bearophile,

  strict denotes a normal function/method, where all the names
 (variable) it uses inside are written down in an explicit way. Some of
 such names are normal function arguments, the other names can be
 global variables, variables from an outer function, instance
 attributes, static class attributes, enums.
 
 // inside here types are optional
  strict(in int y, in z, out k, inout w) int foo(int x) {
 // ... code
 }

I Like the idea but I think that is a bit /to/ explicit. It makes me think of the declared exceptions thing in Java. I don't remember exactly what the problem is there (I've done next to no Java) but being overly explicit seems to me to be an invitation for problems. Might the following get most of the advantages? strict acts like pure but allows the function to modify it's arguments. that plus some relaxed rules about what can be used for default parameters would get >90% of what I see you asking for: int a; void Outer() { int b; strict int Inner(int i, ref j = b, out k = a) { k = j; return i + j; } int m = Inner(); } -- <IXOYE><
Feb 14 2010