Thread overview
[Issue 5007] New: @outer() attribute
Oct 07, 2010
Nick Sabalausky
October 06, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=5007

           Summary: @outer() attribute
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: bearophile_hugs@eml.cc


--- Comment #0 from bearophile_hugs@eml.cc 2010-10-06 14:43:49 PDT ---
Generally it's not a good practice to use global values (or values from outer scopes, D has nested functions too, so names may come from the outer function too), but passed arguments increase the amount of used stack and they may slow down the code a little where high-performance is very important.

So in some situations the programmer may need to use global/outer names. But allowing functions to freely access global scope as in C language may lead to bugs, because there is no control over the flow of information between the subsystems of the program, and also because accidental masking of an outer name is allowed:


int x = 100;
int foo(int y) {
    int x = 5;
    return x + y; // silently uses local x
}
void main() {
    assert(foo(10) == 15);
}


For this (and for other purposes) D has introduced the 'pure' attribute for functions that disallows the access to mutable outer state. But 'pure' is a blunt tool, and in some situations it can't be used. To avoid bugs in such situations, caused by unwanted usage of outer state, an attribute may be defined, it may be named "@outer".

The purpose of the (optional) @outer attribute is similar to the 'global' attribute in the SPARK language:

# global in out CallCount;

A D function that is annotated with @outer must specify all global variables it
uses, and if each of them is just read (in), written to (out), or both (inout).

An example of its possible syntax:


int x = 100;
int y = 200;

@outer(in x, inout y)
int foo(int z) {
    y = x + z;
    return y;
}


Here the compiler enforces that foo() uses only the x and y outer defined
variables, that x is just read and y is both read and written inside foo().
This tidies up the flow of information.

The @outer attribute is optional, and you may avoid its usage in small script-like D programs. But in situations where the D code must be very reliable, a simple automatic code review tool may require the usage of @outer by all functions/methods.

The @outer(...) need to be shown both in the documentation produced by -D and
-X (Json too) dmd compilation switches.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 07, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=5007


Nick Sabalausky <cbkbbejeap@mailinator.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |cbkbbejeap@mailinator.com


--- Comment #1 from Nick Sabalausky <cbkbbejeap@mailinator.com> 2010-10-06 18:34:38 PDT ---
I like the general idea, but why specify the globals you're going to use? Why not something like this:

--------------------
module foo;
int globalVar;
class Foo()
{
    int instanceVar;
    static int classVar;

    @explicitLookup  // Name subject to change
    void bar()
    {

        int globalVar;   // Error
        int instanceVar; // Error
        int classVar;    // Error

        globalVar   = 1; // Error
        instanceVar = 1; // Error
        classVar    = 1; // Error

        .globalVar       = 1; // Ok
        this.instanceVar = 1; // Ok
        Foo.classVar     = 1; // Ok
    }
}
--------------------

And, of course, let it also be used like like this:

--------------------
module foo;
@explicitLookup: // Applies to all code below
int globalVar;
class Foo()
{
    int instanceVar;
    static int classVar;

    void bar()
    {
        globalVar   = 1; // Error
        instanceVar = 1; // Error
        classVar    = 1; // Error

        .globalVar       = 1; // Ok
        this.instanceVar = 1; // Ok
        Foo.classVar     = 1; // Ok
    }
}
--------------------

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 07, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=5007



--- Comment #2 from bearophile_hugs@eml.cc 2010-10-06 19:24:03 PDT ---
(In reply to comment #1)

> but why specify the globals you're going to use?

It's like in Contract Programming, where your contracts state what are the conditions on the function inputs and outputs (and when the "old" will be available the contracts will also be able to specify at high level some of the changes).

The @outer is like a contract that specifies what's the allowed flux of information in and out of a function. Reducing unwanted and unforeseen flux of information between subsystems is a very good way to reduce the complexity of the whole design.

So @outer() is similar to a second signature of the function. Beside the normal
signature that states the types and in/out/ref nature of the explicit function
arguments, the @outer() allows to specify the names and in/out/ref nature of
the implicit (== from outer scopes) names used by the function.


>         this.instanceVar = 1; // Ok

Many programmers don't like this (despite it's the way Python code is written).


>         Foo.classVar     = 1; // Ok

The need to prefix static members with the class/struct name is something I'd like to be enforced on default.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 25, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5007



--- Comment #3 from bearophile_hugs@eml.cc 2011-06-24 17:16:06 PDT ---
See for more comments:

http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=139389

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 23, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5007



--- Comment #4 from bearophile_hugs@eml.cc 2013-10-23 02:53:02 PDT ---
See also: http://nimrod-code.org/blog/writetracking.html

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------