digitalmars.D - Ironclad C++
- bearophile (20/31) Aug 03 2013 "Ironclad C++, A Library-Augmented Type-Safe Subset of C++" by
- Walter Bright (3/7) Aug 03 2013 The problem with different pointer types is, of course, what do you do w...
- Timon Gehr (2/12) Aug 03 2013 Why would that be a problem?
- Walter Bright (4/18) Aug 03 2013 Consider the canonical example:
-
Timon Gehr
(2/21)
Aug 03 2013
No, you use lptr
because it is the most specialized type that work... - Walter Bright (2/26) Aug 03 2013 Then the pointer coming out is more specialized than the pointer that we...
-
Timon Gehr
(8/38)
Aug 03 2013
Yes, but as far as I understood it you can assign lptr
back to - Walter Bright (3/10) Aug 03 2013 I don't believe it is easily addressed or someone would have done so by ...
- Kagamin (2/3) Aug 04 2013 Why?
- deadalnix (6/9) Aug 04 2013 It only work for qualifiers. The same issue arise in much for
- Walter Bright (2/4) Aug 04 2013 This is where attribute inference comes into play.
- Timon Gehr (2/6) Aug 04 2013 (He is talking about runtime parameters.)
- Timon Gehr (66/69) Aug 04 2013 Off the top of my head:
- bearophile (14/15) Aug 04 2013 Thank you.
- Timon Gehr (9/25) Aug 04 2013 Maybe, but this is not my decision, and if it is removed it should be
- bearophile (5/8) Aug 04 2013 I think you have too much faith in people intelligence (or just
- Timon Gehr (4/12) Aug 04 2013 In case someone wants to try anyway, eg. the following course is quite
- Andre Artus (2/20) Aug 04 2013 Thanks Timon, this looks like a great resource.
- Kagamin (2/5) Aug 05 2013 How would you account for yet undefined features like ARC?
- Walter Bright (2/3) Aug 04 2013 If these are not in bugzilla, please add them.
- Timon Gehr (3/6) Aug 04 2013 I have reported the unsoundness:
- Walter Bright (2/10) Aug 04 2013 Please add all 4, not just the last one.
- Kagamin (21/24) Aug 05 2013 OK, but I'm not sure naming and scoping buys you anything except
- Timon Gehr (19/42) Aug 05 2013 I thought I had demonstrated that it buys you more. It resolves the
- Kagamin (11/30) Aug 06 2013 It may look ambiguous to someone who doesn't know, how the
- Kagamin (2/4) Aug 06 2013 Though it must be viral in order to work.
- deadalnix (4/6) Aug 06 2013 In shown examples, 2 function signatures are involved. If you
- Kagamin (3/10) Aug 09 2013 Semantics of inout doesn't depend on the number of functions.
- deadalnix (4/15) Aug 09 2013 It is ambiguous if the inout of the function passed as parameter
- H. S. Teoh (35/52) Aug 09 2013 The meaning of inout basically means that whatever the type qualifiers
- Kagamin (4/7) Aug 15 2013 See my explanation, how inout works and why your example ignores
- deadalnix (7/14) Aug 15 2013 Dude I've read that. Your definition isn't helping in any way to
- Timon Gehr (4/13) Aug 06 2013 ???
- Kagamin (3/5) Aug 09 2013 It's just an unintended implementation error for a case which was
- deadalnix (18/49) Aug 05 2013 The ambiguity lies in the fact that inout in the delegate may
- Kagamin (7/14) Aug 06 2013 inout applies to parameters and is transitive, but delegate's
- Araq (2/5) Aug 04 2013 Doesn't D already have that problem with its immutable/const
- Walter Bright (4/11) Aug 04 2013 Yes, and we've gone to considerable effort to deal with it, and there ar...
"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
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
On 08/04/2013 01:55 AM, Walter Bright wrote:On 8/3/2013 4:32 PM, bearophile wrote:Why would that be a problem?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
On 8/3/2013 5:49 PM, Timon Gehr wrote:On 08/04/2013 01:55 AM, Walter Bright wrote:Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?On 8/3/2013 4:32 PM, bearophile wrote:Why would that be a problem?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
On 08/04/2013 04:06 AM, Walter Bright wrote:On 8/3/2013 5:49 PM, Timon Gehr wrote:No, you use lptr<void> because it is the most specialized type that works.On 08/04/2013 01:55 AM, Walter Bright wrote:Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?On 8/3/2013 4:32 PM, bearophile wrote:Why would that be a problem?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
On 8/3/2013 7:08 PM, Timon Gehr wrote:On 08/04/2013 04:06 AM, Walter Bright wrote:Then the pointer coming out is more specialized than the pointer that went in?On 8/3/2013 5:49 PM, Timon Gehr wrote:No, you use lptr<void> because it is the most specialized type that works.On 08/04/2013 01:55 AM, Walter Bright wrote:Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?On 8/3/2013 4:32 PM, bearophile wrote:Why would that be a problem?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
On 08/04/2013 04:28 AM, Walter Bright wrote:On 8/3/2013 7:08 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? (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.)On 08/04/2013 04:06 AM, Walter Bright wrote:Then the pointer coming out is more specialized than the pointer that went in?On 8/3/2013 5:49 PM, Timon Gehr wrote:No, you use lptr<void> because it is the most specialized type that works.On 08/04/2013 01:55 AM, Walter Bright wrote:Consider the canonical example: void* foo(void *p) { return p; } Do you write an overload for each kind of pointer?On 8/3/2013 4:32 PM, bearophile wrote:Why would that be a problem?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
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
On Sunday, 4 August 2013 at 02:41:18 UTC, Timon Gehr wrote:D's inout is a somewhat failed attemptWhy?
Aug 04 2013
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: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 ?D's inout is a somewhat failed attemptWhy?
Aug 04 2013
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
On 08/04/2013 08:35 PM, Walter Bright wrote:On 8/4/2013 7:04 AM, deadalnix wrote:(He is talking about runtime parameters.)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
On 08/04/2013 11:51 AM, Kagamin wrote:On Sunday, 4 August 2013 at 02:41:18 UTC, Timon Gehr wrote: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); // (!) }D's inout is a somewhat failed attemptWhy?
Aug 04 2013
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
On 08/04/2013 06:18 PM, bearophile wrote:Timon Gehr:Maybe, but this is not my decision, and if it is removed it should be replaced.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.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
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
On 08/04/2013 11:55 PM, bearophile wrote:Timon Gehr:In case someone wants to try anyway, eg. the following course is quite enjoyable: http://www.cis.upenn.edu/~bcpierce/sf/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
On Sunday, 4 August 2013 at 22:26:19 UTC, Timon Gehr wrote:On 08/04/2013 11:55 PM, bearophile wrote:Thanks Timon, this looks like a great resource.Timon Gehr:In case someone wants to try anyway, eg. the following course is quite enjoyable: http://www.cis.upenn.edu/~bcpierce/sf/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
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
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
On 08/05/2013 12:35 AM, Walter Bright wrote:On 8/4/2013 8:04 AM, Timon Gehr wrote:I have reported the unsoundness: http://d.puremagic.com/issues/show_bug.cgi?id=10758Off the top of my head:If these are not in bugzilla, please add them.
Aug 04 2013
On 8/4/2013 4:03 PM, Timon Gehr wrote:On 08/05/2013 12:35 AM, Walter Bright wrote:Please add all 4, not just the last one.On 8/4/2013 8:04 AM, Timon Gehr wrote:I have reported the unsoundness: http://d.puremagic.com/issues/show_bug.cgi?id=10758Off the top of my head:If these are not in bugzilla, please add them.
Aug 04 2013
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
On 08/05/2013 10:44 PM, Kagamin wrote:On Sunday, 4 August 2013 at 15:04:48 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.- 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.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.Those ideas are more than 40 years old and this is a minor adaptation.- 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,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?The fix is to introduce proper scoping, but then it does not seem sensible to only allow one name for the type constructor parameter.- 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. ...
Aug 05 2013
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
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
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
On Tuesday, 6 August 2013 at 16:55:43 UTC, deadalnix wrote:On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:Semantics of inout doesn't depend on the number of functions. What is ambiguous in the given description?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 09 2013
On Friday, 9 August 2013 at 14:47:23 UTC, Kagamin wrote:On Tuesday, 6 August 2013 at 16:55:43 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.On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:Semantics of inout doesn't depend on the number of functions. What is ambiguous in the given description?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 09 2013
On Fri, Aug 09, 2013 at 07:00:49PM +0200, deadalnix wrote:On Friday, 9 August 2013 at 14:47:23 UTC, Kagamin wrote: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!On Tuesday, 6 August 2013 at 16:55:43 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.On Tuesday, 6 August 2013 at 15:13:18 UTC, Kagamin wrote:Semantics of inout doesn't depend on the number of functions. What is ambiguous in the given description?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 09 2013
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
On Friday, 16 August 2013 at 05:48:12 UTC, Kagamin wrote:On Friday, 9 August 2013 at 17:00:53 UTC, deadalnix wrote: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.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
On 08/06/2013 05:13 PM, Kagamin wrote:On Tuesday, 6 August 2013 at 02:11:54 UTC, Timon Gehr wrote:??? Nothing subjective about this! Even DMD does not know how the feature works in this case.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. ...
Aug 06 2013
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
On Sunday, 4 August 2013 at 15:04:48 UTC, Timon Gehr wrote:On 08/04/2013 11:51 AM, Kagamin wrote: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.On Sunday, 4 August 2013 at 02:41:18 UTC, Timon Gehr wrote: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); }D's inout is a somewhat failed attemptWhy?// 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
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
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
On 8/4/2013 3:48 AM, Araq wrote: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.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