How mutable is immutable?

Timon Gehr timon.gehr at gmx.ch
Thu Oct 18 10:43:59 PDT 2012


On 10/18/2012 10:08 AM, Don Clugston wrote:
> On 17/10/12 18:02, Timon Gehr wrote:
>> On 10/17/2012 01:49 PM, Don Clugston wrote:
>>> ...
>>>
>>> That's the point -- *which* checks are missing from @safe?
>>
>> Escaping stack data and arbitrarily freeing memory are not operations
>> found in memory safe languages.
>
> HOW do you propose to check for escaping stack data?
>

Static escape analysis. Use the 'scope' qualifier to designate
data that is not allowed to be escaped in order to make it modular.

> ...
>>
>> The implementation of the 'scope' storage class should be fixed. We
>> could then require an unsafe cast(scope) to disable prevention of stack
>> address escaping.
>
> No we can't. f cannot know that the string it has been given is on the
> stack. So main() must prevent it from being given to f() in the first
> place. How can it do that?
>

f can know that it mustn't escape it, which is enough.

> void foo(bool b, string y)
> {
>    immutable (char)[4] x = "abba";
>    string s = b ? x : y;
>    f(s);
> }
>
> Make it safe.
>

It is safe if the parameter to f is marked with 'scope'. (and this in
turn obliges f not to escape it.)

Analyze scope on the expression level.

The analysis would determine that x[] is 'scope'. It would
conservatively propagate this fact to (b ? x[] : y). Then the local
variable 's' will get the 'scope' storage class.

In general, use a fixed-point iteration to determine all local
variables that might refer to scope'd data and prevent that they get
escaped.

>
>> Rust's borrowed pointers may give some hints on how
>> to extend 'scope' to fields of structs.
>
> I think it is more fundamental than that.
>
>> As to delete, delete is as unsafe when the involved data is immutable
>> as when it is mutable. Why require an additional cast in one case?
>
> This is not about safety.
> Modifying immutable data breaks the type system. Deleting mutable data
> does not.
> AFAIK it is safe to implement delete as a call to the
> finalizer, followed by setting the memory to T.init.
> ...


Now I see where you are coming from. This is indeed a safe approach for
references to/arrays of fully mutable value types, but not for delete
in general.

Make sure to treat void* specially though.

struct S{ immutable int x; this(int x){this.x=x;}}

void main()@safe{
     void* s = new S(2);
     delete s;
}

Class instance memory does not have a T.init, because it is not
assigned a T. And even if it was, how would you know at compile time if
the bound instance has any immutable fields?
Should that be a runtime exception?



More information about the Digitalmars-d mailing list