Difference between revisions of "DIP25"

From D Wiki
Jump to: navigation, search
(Typechecking rules)
(Typechecking rules)
Line 73: Line 73:
  
 
# An invocation of a function that takes a parameter of type <code>ref T</code> may pass one of the following:
 
# An invocation of a function that takes a parameter of type <code>ref T</code> may pass one of the following:
## An lvalue of type <code>T</code>, including array and <code>struct</code> members;
+
## An lvalue of type <code>T</code>, including function arguments, array and <code>struct</code> members;
 
## The result of a function returning <code>ref T</code>.
 
## The result of a function returning <code>ref T</code>.
 
# A function that returns a <code>ref T</code> may return one of the following:
 
# A function that returns a <code>ref T</code> may return one of the following:
Line 82: Line 82:
 
## The invocation of a function <code>fun</code> returning <code>ref T</code> IF <code>fun</code> does NOT take any parameters of type <code>T</code> or <code>S<sub>T</sub></code>.
 
## The invocation of a function <code>fun</code> returning <code>ref T</code> IF <code>fun</code> does NOT take any parameters of type <code>T</code> or <code>S<sub>T</sub></code>.
 
## The invocation of a function <code>fun</code> returning <code>ref T</code> IF none of <code>fun</code>'s parameters of type <code>ref T</code> and <code>ref S</code> are bound to local variables.
 
## The invocation of a function <code>fun</code> returning <code>ref T</code> IF none of <code>fun</code>'s parameters of type <code>ref T</code> and <code>ref S</code> are bound to local variables.
 +
 +
=== Discussion and Examples ===
 +
 +
The rules allow unrestricted pass-down and conservatively restrict pass-up to avoid escaping values. Itemized discussion follows
 +
 +
1.1 Regular lvalues can be passed down:
 +
 +
<syntaxhighlight lang=D>
 +
void fun(ref T);
 +
 +
struct S { int a; T b; }
 +
 +
void caller(T v1, S v2) {
 +
    static T v3;
 +
    T v4;
 +
    static S v5;
 +
    S v6;
 +
 +
    // Fine: pass parameter
 +
    fun(v1);
 +
    fun(v2.b);
 +
    // Fine: pass static lvalue
 +
    fun(v3);
 +
    // Fine: pass of stack variable
 +
    fun(v4);
 +
    // Fine: pass member of static struct
 +
    fun(v5.b);
 +
    // Fine: pass member of local struct
 +
    fun(v6.b);
 +
}
  
 
== Copyright ==
 
== Copyright ==
 
This document has been placed in the Public Domain.
 
This document has been placed in the Public Domain.

Revision as of 06:08, 6 February 2013

DIP25: Sealed references

Title: Sealed references
DIP: 25
Version: 1
Status: Draft
Created: 2013-02-05
Last Modified: 2013-02-05
Author: Andrei Alexandrescu and Walter Bright
Links:

Abstract

D offers a number of features aimed at systems-level coding, such as unrestricted pointers, casting between integers and pointers, and the @system attribute. These means, combined with the other features of D, make it a complete and expressive language for systems-level tasks. On the other hand, economy of means should be exercised in defining such powerful but dangerous features. Most other features should offer good safety guarantees with little or no loss in efficiency or expressiveness. This proposal makes ref provide such a guarantee: with the proposed rules, it is impossible in safe code to have ref refer to a destroyed object. The restrictions introduced are not backward compatible, but disallow code that is stylistically questionable and that can be easily replaced either with equivalent and clearer code.

In a nutshell

Description

Currently, D has some provisions for avoiding dangling references:

ref int fun(int x) {
  return x; // Error: escaping reference to local variable x 
}

ref int gun() {
  int x;
  return x; // Error: escaping reference to local variable x 
}

However, this enforcement is shallow. The following code compiles and allows reads and writes through defunct stack locations, bypassing scoping and lifetime rules:

ref int id(ref int x) {
  return x; 
}

ref int fun(int x) {
  return id(x); 
}

ref int gun() {
  int x;
  return id(x); 
}

The escape pattern is obvious in this simple example with all code in sight, and may be found automatically. The problem is that generally the compiler cannot see the body of id. We need to devise a method for compiling such functions separately.

We want to devise rules that allow us to pass objects by reference down into functions, and return references up from functions, while disallowing cases such as the above when a reference passed up ends up referring to a deallocated temporary.

Typechecking rules

The rules below discuss under what circumstances functions receiving and/or returning ref T may be called, where T is some arbitrary type. Let us also denote with ST any struct that has a non-static member variable of type T.

  1. An invocation of a function that takes a parameter of type ref T may pass one of the following:
    1. An lvalue of type T, including function arguments, array and struct members;
    2. The result of a function returning ref T.
  2. A function that returns a ref T may return one of the following:
    1. A static lvalue of type T, including members of static struct values;
    2. A member variable of type T belonging to a class object;
    3. A ref T parameter;
    4. A member of type T of ST that has been passed as ref ST into the function;
    5. The invocation of a function fun returning ref T IF fun does NOT take any parameters of type T or ST.
    6. The invocation of a function fun returning ref T IF none of fun's parameters of type ref T and ref S are bound to local variables.

Discussion and Examples

The rules allow unrestricted pass-down and conservatively restrict pass-up to avoid escaping values. Itemized discussion follows

1.1 Regular lvalues can be passed down:

<syntaxhighlight lang=D> void fun(ref T);

struct S { int a; T b; }

void caller(T v1, S v2) {

   static T v3;
   T v4;
   static S v5;
   S v6;
   // Fine: pass parameter
   fun(v1);
   fun(v2.b);
   // Fine: pass static lvalue
   fun(v3);
   // Fine: pass of stack variable
   fun(v4);
   // Fine: pass member of static struct
   fun(v5.b);
   // Fine: pass member of local struct
   fun(v6.b);

}

Copyright

This document has been placed in the Public Domain.