www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ironclad C++

reply "bearophile" <bearophileHUGS lycos.com> writes:
"Ironclad C++, A Library-Augmented Type-Safe Subset of C++" by 
Christian DeLozier et al:
http://repository.upenn.edu/cis_reports/982/

It's a strict subset of C++ plus added some libraries and some 
static verifiers. The purpose is to have a safer C++. It has some 
similarities with D.

There are many small differences between C++ and Ironclad C++, 
one of them is that all pointers must be smart pointers. It also 
uses a precise garbage collection.

In my opinion what's most interesting is what it does for Stack 
Deallocation Safety, it uses dynamic lifetime checking, with two 
smart pointers, page 5-8:

Prior work on preventing use-after-free errors has introduced 
some notion of a local pointer [10, 18], but these efforts have 
been focused on purely static enforcement through sophisticated 
program analyses. Local pointers in Ironclad C++ combine static 
enforcement and dynamic checking, providing flexibility and 
simplifying the necessary analysis.<
Local pointers record the lower bound on addresses that they may 
point to. Through a combination of static restrictions and 
dynamic checks, these local pointers are allowed to point only 
to heap-allocated values or values at the same level or above in 
the call stack.<
The paper explains the various cases: assign from ptr<T> into lptr<T>, assign from lptr<T> into ptr<T>, and assign from lptr<T> into lptr<T>. So with a mix of run-time tests and a small amount of static analysis the code is safe and fast enough. It seems a simple enough idea. Bye, bearophile
Aug 03 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 4:32 PM, bearophile wrote:
 The paper explains the various cases: assign from ptr<T> into lptr<T>, assign
 from lptr<T> into ptr<T>, and assign from lptr<T> into lptr<T>.

 So with a mix of run-time tests and a small amount of static analysis the code
 is safe and fast enough. It seems a simple enough idea.
The problem with different pointer types is, of course, what do you do with functions that take pointers as arguments?
Aug 03 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/04/2013 01:55 AM, Walter Bright wrote:
 On 8/3/2013 4:32 PM, bearophile wrote:
 The paper explains the various cases: assign from ptr<T> into lptr<T>,
 assign
 from lptr<T> into ptr<T>, and assign from lptr<T> into lptr<T>.

 So with a mix of run-time tests and a small amount of static analysis
 the code
 is safe and fast enough. It seems a simple enough idea.
The problem with different pointer types is, of course, what do you do with functions that take pointers as arguments?
Why would that be a problem?
Aug 03 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 5:49 PM, Timon Gehr wrote:
 On 08/04/2013 01:55 AM, Walter Bright wrote:
 On 8/3/2013 4:32 PM, bearophile wrote:
 The paper explains the various cases: assign from ptr<T> into lptr<T>,
 assign
 from lptr<T> into ptr<T>, and assign from lptr<T> into lptr<T>.

 So with a mix of run-time tests and a small amount of static analysis
 the code
 is safe and fast enough. It seems a simple enough idea.
The problem with different pointer types is, of course, what do you do with functions that take pointers as arguments?
Why would that be a problem?
Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?
Aug 03 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/04/2013 04:06 AM, Walter Bright wrote:
 On 8/3/2013 5:49 PM, Timon Gehr wrote:
 On 08/04/2013 01:55 AM, Walter Bright wrote:
 On 8/3/2013 4:32 PM, bearophile wrote:
 The paper explains the various cases: assign from ptr<T> into lptr<T>,
 assign
 from lptr<T> into ptr<T>, and assign from lptr<T> into lptr<T>.

 So with a mix of run-time tests and a small amount of static analysis
 the code
 is safe and fast enough. It seems a simple enough idea.
The problem with different pointer types is, of course, what do you do with functions that take pointers as arguments?
Why would that be a problem?
Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?
No, you use lptr<void> because it is the most specialized type that works.
Aug 03 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 7:08 PM, Timon Gehr wrote:
 On 08/04/2013 04:06 AM, Walter Bright wrote:
 On 8/3/2013 5:49 PM, Timon Gehr wrote:
 On 08/04/2013 01:55 AM, Walter Bright wrote:
 On 8/3/2013 4:32 PM, bearophile wrote:
 The paper explains the various cases: assign from ptr<T> into lptr<T>,
 assign
 from lptr<T> into ptr<T>, and assign from lptr<T> into lptr<T>.

 So with a mix of run-time tests and a small amount of static analysis
 the code
 is safe and fast enough. It seems a simple enough idea.
The problem with different pointer types is, of course, what do you do with functions that take pointers as arguments?
Why would that be a problem?
Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?
No, you use lptr<void> because it is the most specialized type that works.
Then the pointer coming out is more specialized than the pointer that went in?
Aug 03 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/04/2013 04:28 AM, Walter Bright wrote:
 On 8/3/2013 7:08 PM, Timon Gehr wrote:
 On 08/04/2013 04:06 AM, Walter Bright wrote:
 On 8/3/2013 5:49 PM, Timon Gehr wrote:
 On 08/04/2013 01:55 AM, Walter Bright wrote:
 On 8/3/2013 4:32 PM, bearophile wrote:
 The paper explains the various cases: assign from ptr<T> into
 lptr<T>,
 assign
 from lptr<T> into ptr<T>, and assign from lptr<T> into lptr<T>.

 So with a mix of run-time tests and a small amount of static analysis
 the code
 is safe and fast enough. It seems a simple enough idea.
The problem with different pointer types is, of course, what do you do with functions that take pointers as arguments?
Why would that be a problem?
Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?
No, you use lptr<void> because it is the most specialized type that works.
Then the pointer coming out is more specialized than the pointer that went in?
Yes, but as far as I understood it you can assign lptr<void> back to ptr<void> implicitly by paying for a runtime check. It's what D will be doing with T* <-> ref T, right? (The general problem is easily addressed at the type system level using some kind of parametric polymorphism, but they don't do that. D's inout is a somewhat failed attempt that gets quite close to solving the issue for the mutability qualifiers.)
Aug 03 2013
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 7:41 PM, Timon Gehr wrote:
 Yes, but as far as I understood it you can assign lptr<void> back to ptr<void>
 implicitly by paying for a runtime check. It's what D will be doing with T* <->
 ref T, right?
I thought the idea was to use the type system to avoid runtime checks.
 (The general problem is easily addressed at the type system level using some
 kind of parametric polymorphism, but they don't do that. D's inout is a
somewhat
 failed attempt that gets quite close to solving the issue for the mutability
 qualifiers.)
I don't believe it is easily addressed or someone would have done so by now.
Aug 03 2013
prev sibling parent reply "Kagamin" <spam here.lot> writes:
On Sunday, 4 August 2013 at 02:41:18 UTC, Timon Gehr wrote:
 D's inout is a somewhat failed attempt
Why?
Aug 04 2013
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 4 August 2013 at 09:52:01 UTC, Kagamin wrote:
 On Sunday, 4 August 2013 at 02:41:18 UTC, Timon Gehr wrote:
 D's inout is a somewhat failed attempt
Why?
It only work for qualifiers. The same issue arise in much for various form where inout can't do anything. What a bout a function which is pure depending on if a function passed as parameter is pure or not ? or return a function the same way ?
Aug 04 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/4/2013 7:04 AM, deadalnix wrote:
 What a bout a function which is pure depending on if a function passed as
 parameter is pure or not ? or return a function the same way ?
This is where attribute inference comes into play.
Aug 04 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/04/2013 08:35 PM, Walter Bright wrote:
 On 8/4/2013 7:04 AM, deadalnix wrote:
 What a bout a function which is pure depending on if a function passed as
 parameter is pure or not ? or return a function the same way ?
This is where attribute inference comes into play.
(He is talking about runtime parameters.)
Aug 04 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/04/2013 11:51 AM, Kagamin wrote:
 On Sunday, 4 August 2013 at 02:41:18 UTC, Timon Gehr wrote:
 D's inout is a somewhat failed attempt
Why?
Off the top of my head: - No naming or scoping: // is this ok? inout(int)* foo(inout(int)* a, inout(int)* delegate(inout(int)*) dg){ return dg(a); } // is this ok? int b; const(int) c; int bar(inout(int)* a, inout(int)* delegate(inout(int)*) dg){ return *dg(a)+*dg(&b)+*dg(&c); } void main(){ immutable int a; // which of those is valid? take your pick. assert(foo(&a,(typeof(a)* x)=>x) is a); assert(!bar(&a,(inout(int)* x)=>x)); } (Apparently, currently both crash the compiler in mtype.c:1894.) Assuming some kind of polymorphic type system allowing at least named type constructor parameters, we can express both: // (details will vary here, eg. if the language is fully dependently typed, this concept can likely be expressed within it.) alias const_immutable_or_mutable TC; C(int)* foo[TC C](C(int)* a, C(int)* delegate(C(int)*) dg){ return dg(a); } int b; const(int) c; int bar[TC A](A(int)* a, B(int)* delegate[TC B](B(int)*) dg){ return *dg(a)+*dg(&b)+*dg(&c); } void main(){ immutable int a; // everything is fine now: assert(foo(&a,x=>x) is a); assert(!bar(&a,x=>x)); } (Here [ ] parameters introduce universal quantification: There is only one foo function, that works for every such type constructor argument, but you cannot find out what that argument was from within the function in order to change its behaviour. This is similar to inout except that it allows naming and scoping.) - Only works for parameters or stack based variables: Tuple!(inout(int)*, inout(int)*) foo(inout(int)* x){ return tuple(x,x); } /usr/include/dmd/phobos/std/typecons.d(363): Error: variable std.typecons.Tuple!(inout(int)*,inout(int)*).Tuple._field_field_0 only parameters or stack based variables can be inout - Plain unsoundness of current type checking approach: The following compiles and runs without errors with DMD: int* foo(inout(int)* x) safe{ inout(int)* screwUp(inout(int)*){ return x; } return screwUp((int*).init); } void main(){ immutable x = 123; static assert(is(typeof(*&x)==immutable)); assert(*&x==123); immutable(int)* y = &x; *foo(y)=456; assert(*&x==456); assert(x!=*&x); // (!) }
Aug 04 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Timon Gehr:

 Off the top of my head:
Thank you. Is it right to add 'inout' the list of D2 features that will be deprecated and later removed? There are "simple" features, like a support for structurally typed tuples, that maybe can be designed well enough with the traditional method. But perhaps when we/you want to modify/add something in the D type system it's better to first find a person able to write down a formal proof of soundness of the idea, and only later decide if it's worth implementing. I am starting to think that to design type system features sometimes you need formal mathematics, otherwise you build a Swiss cheese. Bye, bearophile
Aug 04 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/04/2013 06:18 PM, bearophile wrote:
 Timon Gehr:

 Off the top of my head:
Thank you. Is it right to add 'inout' the list of D2 features that will be deprecated and later removed? ...
Maybe, but this is not my decision, and if it is removed it should be replaced.
 There are "simple" features, like a support for structurally typed
 tuples, that maybe can be designed well enough with the traditional
 method. But perhaps when we/you want to modify/add something in the D
 type system it's better to first find a person able to write down a
 formal proof of soundness of the idea, and only later decide if it's
 worth implementing.
Formal proofs require a formalization of language semantics. It's not just a matter of finding someone to carry out the proof. (Anyone can learn online how to do this.)
 I am starting to think that to design type system
 features sometimes you need formal mathematics, otherwise you build a
 Swiss cheese.
 ...
This is not only true for type checkers, but for also for other kinds of programs. Yet most programming languages do not allow expressing a significant amount of checkable non-trivial correctness properties.
Aug 04 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Timon Gehr:

 Formal proofs require a formalization of language semantics. 
 It's not just a matter of finding someone to carry out the 
 proof. (Anyone can learn online how to do this.)
I think you have too much faith in people intelligence (or just in my intelligence) :-) Bye, bearophile
Aug 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/04/2013 11:55 PM, bearophile wrote:
 Timon Gehr:

 Formal proofs require a formalization of language semantics. It's not
 just a matter of finding someone to carry out the proof. (Anyone can
 learn online how to do this.)
I think you have too much faith in people intelligence (or just in my intelligence) :-) Bye, bearophile
In case someone wants to try anyway, eg. the following course is quite enjoyable: http://www.cis.upenn.edu/~bcpierce/sf/
Aug 04 2013
parent "Andre Artus" <andre.artus gmail.com> writes:
On Sunday, 4 August 2013 at 22:26:19 UTC, Timon Gehr wrote:
 On 08/04/2013 11:55 PM, bearophile wrote:
 Timon Gehr:

 Formal proofs require a formalization of language semantics. 
 It's not
 just a matter of finding someone to carry out the proof. 
 (Anyone can
 learn online how to do this.)
I think you have too much faith in people intelligence (or just in my intelligence) :-) Bye, bearophile
In case someone wants to try anyway, eg. the following course is quite enjoyable: http://www.cis.upenn.edu/~bcpierce/sf/
Thanks Timon, this looks like a great resource.
Aug 04 2013
prev sibling parent "Kagamin" <spam here.lot> writes:
On Sunday, 4 August 2013 at 16:18:48 UTC, bearophile wrote:
 I am starting to think that to design type system features 
 sometimes you need formal mathematics, otherwise you build a 
 Swiss cheese.
How would you account for yet undefined features like ARC?
Aug 05 2013
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/4/2013 8:04 AM, Timon Gehr wrote:
 Off the top of my head:
If these are not in bugzilla, please add them.
Aug 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/05/2013 12:35 AM, Walter Bright wrote:
 On 8/4/2013 8:04 AM, Timon Gehr wrote:
 Off the top of my head:
If these are not in bugzilla, please add them.
I have reported the unsoundness: http://d.puremagic.com/issues/show_bug.cgi?id=10758
Aug 04 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/4/2013 4:03 PM, Timon Gehr wrote:
 On 08/05/2013 12:35 AM, Walter Bright wrote:
 On 8/4/2013 8:04 AM, Timon Gehr wrote:
 Off the top of my head:
If these are not in bugzilla, please add them.
I have reported the unsoundness: http://d.puremagic.com/issues/show_bug.cgi?id=10758
Please add all 4, not just the last one.
Aug 04 2013
prev sibling next sibling parent reply "Kagamin" <spam here.lot> writes:
On Sunday, 4 August 2013 at 15:04:48 UTC, Timon Gehr wrote:

 - No naming or scoping:
OK, but I'm not sure naming and scoping buys you anything except for being more explicit, but explicity vs implicity is a tradeoff. I kinda understand the argument about dependent purity, but the problem with purity arises mostly in generic code consuming arbitrary ranges, the problem with delegate purity looks minor. As to the crash, it looks like it tries to mess with the delegate's signature, which it souldn't do: delegate's signature doesn't participate in const transitivity rules. The cost is probably one if at the right place.
 - Only works for parameters or stack based variables:
Not a failure to not do what is not proved to be possible and acceptable. Const system doesn't interoperate with templates well. You don't have a solution either, even with your universal notation, right?
 - Plain unsoundness of current type checking approach:
Closures were not covered in DIP2 (I agree, that was a major overlook). Closured variables should be treated as external to the closure and either be seen as const or require cast to const. Fix may be non-trivial, but possible. I was thinking to call for lore about issues with inout and solve them, also for other people, who want to work on the type system to have an estimate of the problem's scale. Am I late?
Aug 05 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/05/2013 10:44 PM, Kagamin wrote:
 On Sunday, 4 August 2013 at 15:04:48 UTC, Timon Gehr wrote:

 - No naming or scoping:
OK, but I'm not sure naming and scoping buys you anything except for being more explicit, but explicity vs implicity is a tradeoff.
I thought I had demonstrated that it buys you more. It resolves the problem that scoping is ambiguous and that there can be only one 'inout' substitution per function application.
 I kinda understand the argument about dependent purity, but the problem
 with purity arises mostly in generic code consuming arbitrary ranges,
 the problem with delegate purity looks minor.
Why? It is the same kind of problem.
 As to the crash, it looks like it tries to mess with the delegate's
 signature, which it souldn't do: delegate's signature doesn't
 participate in const transitivity rules. The cost is probably one if at
 the right place.

 - Only works for parameters or stack based variables:
Not a failure to not do what is not proved to be possible and acceptable.
Those ideas are more than 40 years old and this is a minor adaptation.
 Const system doesn't interoperate with templates well.
 You don't have a solution either,
Of course. Just push the parameter to the instantiated struct type. i.e. struct S(T){ T field; } S!(C(int)*) foo[TC C](C(int)* p){ return typeof(return)(p); } Would behave like: struct S[TC C]{ // (template instance) C(int)* field; } S![C] foo[TC C](C(int)* p){ return typeof(return)(p); }
 even with your universal notation, right?

 - Plain unsoundness of current type checking approach:
Closures were not covered in DIP2 (I agree, that was a major overlook). Closured variables should be treated as external to the closure and either be seen as const or require cast to const. Fix may be non-trivial, but possible. ...
The fix is to introduce proper scoping, but then it does not seem sensible to only allow one name for the type constructor parameter.
Aug 05 2013
parent reply "Kagamin" <spam here.lot> writes:
On Tuesday, 6 August 2013 at 02:11:54 UTC, Timon Gehr wrote:
 I thought I had demonstrated that it buys you more. It resolves 
 the problem that scoping is ambiguous and that there can be 
 only one 'inout' substitution per function application.
It may look ambiguous to someone who doesn't know, how the feature works, because it's implicit, which, again, is a tradeoff. Subjective ambiguity should be solvable with better docs, learning resources and tutorials.
 Why? It is the same kind of problem.
They differ in scale. Const overloads are an overwhelming problem in OO design, which is vaguely demonstrated in DIP2.
 Of course. Just push the parameter to the instantiated struct 
 type.

 i.e.

 struct S(T){
     T field;
 }

 S!(C(int)*) foo[TC C](C(int)* p){ return typeof(return)(p); }


 Would behave like:

 struct S[TC C]{ // (template instance)
     C(int)* field;
 }

 S![C] foo[TC C](C(int)* p){ return typeof(return)(p); }
Ah, an opaque template parameter? It may have value in itself and not require a new syntax or restricted to type qualifiers.
 The fix is to introduce proper scoping, but then it does not 
 seem sensible to only allow one name for the type constructor 
 parameter.
inout already has proper scoping: data external to the function shouldn't be qualified as inout, it just should be checked.
Aug 06 2013
next sibling parent "Kagamin" <spam here.lot> writes:
On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:
 Ah, an opaque template parameter? It may have value in itself 
 and not require a new syntax or restricted to type qualifiers.
Though it must be viral in order to work.
Aug 06 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:
 inout already has proper scoping: data external to the function 
 shouldn't be qualified as inout, it just should be checked.
In shown examples, 2 function signatures are involved. If you don't understand where the ambiguity lies, I suggest you step back and reconsider the situation.
Aug 06 2013
parent reply "Kagamin" <spam here.lot> writes:
On Tuesday, 6 August 2013 at 16:55:43 UTC, deadalnix wrote:
 On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:
 inout already has proper scoping: data external to the 
 function shouldn't be qualified as inout, it just should be 
 checked.
In shown examples, 2 function signatures are involved. If you don't understand where the ambiguity lies, I suggest you step back and reconsider the situation.
Semantics of inout doesn't depend on the number of functions. What is ambiguous in the given description?
Aug 09 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Friday, 9 August 2013 at 14:47:23 UTC, Kagamin wrote:
 On Tuesday, 6 August 2013 at 16:55:43 UTC, deadalnix wrote:
 On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:
 inout already has proper scoping: data external to the 
 function shouldn't be qualified as inout, it just should be 
 checked.
In shown examples, 2 function signatures are involved. If you don't understand where the ambiguity lies, I suggest you step back and reconsider the situation.
Semantics of inout doesn't depend on the number of functions. What is ambiguous in the given description?
It is ambiguous if the inout of the function passed as parameter stand for the function passed as parameter or the function you pass the parameter to.
Aug 09 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Aug 09, 2013 at 07:00:49PM +0200, deadalnix wrote:
 On Friday, 9 August 2013 at 14:47:23 UTC, Kagamin wrote:
On Tuesday, 6 August 2013 at 16:55:43 UTC, deadalnix wrote:
On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:
inout already has proper scoping: data external to the
function shouldn't be qualified as inout, it just should be
checked.
In shown examples, 2 function signatures are involved. If you don't understand where the ambiguity lies, I suggest you step back and reconsider the situation.
Semantics of inout doesn't depend on the number of functions. What is ambiguous in the given description?
It is ambiguous if the inout of the function passed as parameter stand for the function passed as parameter or the function you pass the parameter to.
The meaning of inout basically means that whatever the type qualifiers are on the parameters, like const, immutable, etc., are automatically propagated to the return type. For example: T func(inout T t) inout { ... return t; } T t; const(T) ct; immutable(T) it; func(t); // return type is T func(ct); // return type is const(T) func(it); // return type is immutable(T) One problem area with inout is that when delegates are involved, the meaning becomes unclear: auto func(inout int delegate(inout x) dg, U parm) inout { // What's the return type of the function? return dg(parm); } Does it mean that dg is an inout parameter, or that dg is a normal parameter, that happens to be an inout delegate of *its* own parameters? Also, is this valid? T func(inout T x, inout T y) inout { return (someCondition) ? x : y; } T t; const(T) ct; immutable(T) it; auto z = func(t, ct); // is this valid? If so, what's the return type? auto w = func(ct, it); // ditto I'm not 100% sure about this. T -- That's not a bug; that's a feature!
Aug 09 2013
prev sibling parent reply "Kagamin" <spam here.lot> writes:
On Friday, 9 August 2013 at 17:00:53 UTC, deadalnix wrote:
 It is ambiguous if the inout of the function passed as 
 parameter stand for the function passed as parameter or the 
 function you pass the parameter to.
See my explanation, how inout works and why your example ignores semantics of inout: http://forum.dlang.org/post/jenapjffdszqqclyxhgc forum.dlang.org
Aug 15 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 16 August 2013 at 05:48:12 UTC, Kagamin wrote:
 On Friday, 9 August 2013 at 17:00:53 UTC, deadalnix wrote:
 It is ambiguous if the inout of the function passed as 
 parameter stand for the function passed as parameter or the 
 function you pass the parameter to.
See my explanation, how inout works and why your example ignores semantics of inout: http://forum.dlang.org/post/jenapjffdszqqclyxhgc forum.dlang.org
Dude I've read that. Your definition isn't helping in any way to resolve the ambiguity we are talking about here, and so the only reasonable assumption I can make at this point is that you didn't understood how the presented cases were ambiguous. Right now you are losing your time and ours, by explaining us something we already know.
Aug 15 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/06/2013 05:13 PM, Kagamin wrote:
 On Tuesday, 6 August 2013 at 02:11:54 UTC, Timon Gehr wrote:
 I thought I had demonstrated that it buys you more. It resolves the
 problem that scoping is ambiguous and that there can be only one
 'inout' substitution per function application.
It may look ambiguous to someone who doesn't know, how the feature works, because it's implicit, which, again, is a tradeoff. Subjective ambiguity should be solvable with better docs, learning resources and tutorials. ...
??? Nothing subjective about this! Even DMD does not know how the feature works in this case.
Aug 06 2013
parent "Kagamin" <spam here.lot> writes:
On Tuesday, 6 August 2013 at 19:26:09 UTC, Timon Gehr wrote:
 Nothing subjective about this! Even DMD does not know how the 
 feature works in this case.
It's just an unintended implementation error for a case which was not explicitly considered. Should be fixable.
Aug 09 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 4 August 2013 at 15:04:48 UTC, Timon Gehr wrote:
 On 08/04/2013 11:51 AM, Kagamin wrote:
 On Sunday, 4 August 2013 at 02:41:18 UTC, Timon Gehr wrote:
 D's inout is a somewhat failed attempt
Why?
Off the top of my head: - No naming or scoping: // is this ok? inout(int)* foo(inout(int)* a, inout(int)* delegate(inout(int)*) dg){ return dg(a); }
The ambiguity lies in the fact that inout in the delegate may stand for foo's inout or delegate's inout. However, in both cases, the sample code should pass.
 // is this ok?
 int b;
 const(int) c;
 int bar(inout(int)* a, inout(int)* delegate(inout(int)*) dg){
     return *dg(a)+*dg(&b)+*dg(&c);
 }
As code accepting inout accept to not modify it, it should also pass. The exact semantic is still unclear, even if equivalent in the sample code above. For instance, it is unclear what should happen in this case : int d; int* qux(int* p) { *p++; return p; } bar(&d, &qux); // Pass for inout at bar's level, do not for inout at delegate level.
 void main(){
     immutable int a;
     // which of those is valid? take your pick.
     assert(foo(&a,(typeof(a)* x)=>x) is a);
     assert(!bar(&a,(inout(int)* x)=>x));
 }

 (Apparently, currently both crash the compiler in mtype.c:1894.)
The last one should pass IMO due to function type conversion rules, whatever case is chosen for inout semantic in case of delegate/function. It is very unclear to me if the first one should pass.
 Assuming some kind of polymorphic type system allowing at least 
 named type constructor parameters, we can express both:

 // (details will vary here, eg. if the language is fully 
 dependently typed, this concept can likely be expressed within 
 it.)
 alias const_immutable_or_mutable TC;
Yes, one way or another, we'll need to be able to alias type qualifiers (or any similar mechanism).
Aug 05 2013
parent "Kagamin" <spam here.lot> writes:
On Tuesday, 6 August 2013 at 03:42:00 UTC, deadalnix wrote:
 The ambiguity lies in the fact that inout in the delegate may 
 stand for foo's inout or delegate's inout.
inout applies to parameters and is transitive, but delegate's signature is not affected by const transitivity rules - it worked this way long before inout was implemented.
 For instance, it is unclear what should happen in this case :
 int d;
 int* qux(int* p) { *p++; return p; }
 bar(&d, &qux); // Pass for inout at bar's level, do not for 
 inout at delegate level.
inout is for functions which return data derived from their parameters, your qux doesn't enforce this semantics: it can return anything which fits int*.
Aug 06 2013
prev sibling parent reply "Araq" <rumpf_a gmx.de> writes:
 Consider the canonical example:

     void* foo(void *p) { return p; }

 Do you write an overload for each kind of pointer?
Doesn't D already have that problem with its immutable/const pointers?
Aug 04 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/4/2013 3:48 AM, Araq wrote:
 Consider the canonical example:

     void* foo(void *p) { return p; }

 Do you write an overload for each kind of pointer?
Doesn't D already have that problem with its immutable/const pointers?
Yes, and we've gone to considerable effort to deal with it, and there are still issues like using the same function for shared vs unshared pointers. Introducing more pointer types makes things exponentially worse.
Aug 04 2013