August 20, 2003 Re: c++ style const concept | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ilya Minkov | The canonical example of a good/useful const_cast in C++ is to avoid duplicate code when you have const and non-const methods that do the same thing. Say I have some kind of array-like class in C++: class MyArray { public: T& operator[](unsigned i) { // (imagine non-trivial code here) return result; } const T& operator[](unsigned i) const { // Without const_cast, I'd be forced to copy & paste (and maintain!) // the non-trivial code from above. However, as the implementor of // this class, I _know_ that this is a perfectly sensible cast, therefore // the language should not get in my way by trying to save me from // myself. return const_cast<MyArray*>(this)->data()[i]; } }; I haven't used D enough to have a good feel for how much it might or might not benefit from having something like C++ const, but I do know that I would definitely miss it from C++ in spite of its shortcomings. It's extra type info, which is quite useful in a very static-type-oriented language such as C++. It is _immensely_ useful to be able to specify all the places that I, the programmer, think that something shouldn't be changed and then enlist the help of the compiler to check all of those places automatically at compile time. Yes it can be used inappropriately, but the fact that a language feature can be abused does not mean it's not useful or does not have its place (witness goto, pointers, unions, inline asm). I find such arguments appealing from a theoretical perspective but inadequate in practice. You could rely on run time tests (DBC/unit tests/assert/whatever), but what if the contract violation happens only under certain rare circumstances? In this case, the compiler has the advantage of seeing _all_ of the code, regardless of how often (or if) it actually gets executed. Even if the unit tests do catch all such violations, I would think it would be preferable to find out about them sooner if it's easy to do so. DBC/unit tests and static type checking are compliments, not substitutes. -- Scott McCaskill "Ilya Minkov" <midiclub@8ung.at> wrote in message news:bhrhij$1suj$1@digitaldaemon.com... Antti Sykäri wrote: > "Dag Brück and others reviewed considerable amounts of real code to see > which casts were casting away const and which of those could be > eliminated using 'mutable'. This study confirmed the conclusion that > "casting away 'const'" cannot be avoided in general and that > 'mutable' appears to eliminate casting away 'const' in less than half of > the cases where it is needed in the absence of 'mutable'." That's about changing existing code - which might be unreasonable... When designing new code, things are different. There is an opinion, that when someone casts away const-ness, this means illogical design which can be avoided from the beginning on. I don't have enough experience to say whether it's true or not, but i would like to think that this statement is true. I'm looking for counter-examples: maybe anyone can give me a hint? -eye |
August 20, 2003 Attributes (was Re: const / immutable (was: C++ style const concept)) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Antti Sykäri | I'm a heavy const user, a true believer in it, I'd say. I'm going to throw out some ideas: How about adding another kind of access specifier, starting with readonly, such that: class A { private T t; // private data member readonly public: // readonly section, also public. this section applies to both rvalues and lvalues of class A T GetT() { return t; } readwrite: // go back to readwrite, still public. This section applies to lvalues this(in T t_) { t = t_; } T SetT(T other) { t = other; return this; } } A couple things I can see from the above: It adds complexity to initialization. I recommend just ignoring all readonly accessors during a constructor, and maybe in the destructor too, or in something obviously lvalue such as an assignment operator. You can avoid having to constantly declare member functions const. Just put it in its own section. This would save the "extra typing" overhead of C++ const quite a bit. readonly and readwrite are a different set of attribute modifiers, totally separate from private public and protected. Orthogonal to. Unrelated. So readonly sections can overlap public/private sections, or be overlapped by them. readonly and readwrite might belong in the same category as mutable. Public, private, protected control the visibility of names to everything outside the class. readonly and readwrite control how the class sees itself (readonly interface, or readonly + readwrite interface) in those member functions, and controls assignability of fields. in, out, and inout control readwrite access to parameters of those functions, and const declares individual data rvalues, which aren't even castable to anything with write access. That's a lot of names for one basic concept (readonly-ness), so perhaps it could all just be called const, or (lack of const) since the usage situation would already make it unambiguous what you meant. This readonly, for the builtin datatypes, and fundamentally, removes the ability to use the assignment operator on such values, or call anything else that's a readwrite member function, on that type. It should also prevent deletion or other forms of destruction/finalization. And the compiler should be able to treat copies of such a value made during periods in which it is sure are all protected by that attribute, that they remain identical so long as it knows the readonly attribute is attached to them. When it becomes unsure, it could save and reload it to make sure any changes are reflected, but I'd rather guarantee that nothing will violate the constraint, ever, during the lifetime of the object or data. The compiler should actively prevent the user from modifying such readonly values or allowing them to be modified whenever possible. If that's too restrictive, use something like mutable, which has different behavior in different situations. I would like to have a kind of constructor that basically allowed the caller to put whatever values they want into the class's fields, by name: this(in); // how would you specify that you want the compiler to generate a method for you, without having to specify any body? // By using prototype only, no body, kinda like C++? It would generate a method for you regardless in C++, but this way you get to control the access. I'd use it like so: class Point { float x,y,z; this(in); // allow construction with the caller being able to initialize the public fields and base class more or less directly this(float x_, float y_, float z_) { x = x_, y = y_, z = z_; } // without that, you have to do this: } new Point a(x:1.0, y:2.0, z:0.0); // call this(in) with initialization for these members new Point a(1.0, 2.0, 0.0); // initialize fields by calling this(float,float,float) or new Point a = { x:1.0; y:2.0, z:0.0 }; // same as this, which I think D allows now? D does named field initialization, right? Maybe structs just automatically work that way. And finally, like C#, I would like to be able to add my own attributes to things. Groups of attributes (private/public/protected would be a group, and so would readonly/readwrite) declared sort of like enums. Unlike anything I've heard of before, you should be able to alias and aggregate these attributes together (a global "alias private readonly notevenIcantouchit;" or "alias public mutable youcanlookbutyoucanttouch"). If you could hook a couple prologue/epilog functions (inlined before and after every function body) to these attributes, then use them to control code generation the same way that contracts work now. Even better, you could use such attributes to *implement* things like contracts. Think about it. What if you declared something akin to an in and out contract yourself? attribute in_custom in { print("in"); assert(this->good()); } attribute out_custom out { print("out"); assert(this->good()); } alias attribute in_custom out_custom invariant_custom; class Sign { invariant_custom: private int x; public this() { x = 0; } bit good() { return x >= 0 && x <= 10; } void badfunction() { ++x; badfunction(); } // will recurse 10 times and then trigger an assert exception! } The compiler would inject the attribute code into each function declared after it class Foo { attribute { my_read assign { assert(false && "don't assign to my_read objects, dumbass!"); } default my_readwrite { } }; // everything up to this point is my_readwrite because it's the default! my_read int x; // if you try to assign this, you'll assert! my_readwrite: // everything else goes here } So there are a bunch of basic "kinds" of modifiers such as in, out, invariant, assign, destroy, copy, create, that sort of thing. To control what situations the code attached to the attribute would apply in. Also these attributes shouldn't run until the constructor for the object has finished, and shouldn't run once the finalizer starts. That way it's guaranteed to have a complete object to deal with. I don't think it would be a good idea to allow decorating member variables with code. Or would it? A member variable or data attribute would control things like assignment, reference, and might serve as an easy way to do properties with a write-through or read-only data field. (The properties in the D spec now may never see the light of day!) Maybe there should be some kind of compile time error for when the compiler can detect at compile time that a code path is going to definitely be executed that contains an assert statement (such as the assign assert above) and issue a compile time error. I guess all this adds to the complexity of the compiler. That's a good thing, in some ways. This could be powerful stuff in the right hands. Maybe could be combined with templates somehow? It's really just the ability to add custom extra type information to your types. One of the major costs of maintenance is having code cut-and-pasted in a bunch of places, as it is hard to change something if it's scattered all over the place. With attributes you can write boilerplate code and attach it to things with an attribute in its declaration. This is good because it keeps such code in one place, in the attribute definition, rather than cut and pasted into every copy of every function that needs it. In C / C++ you have to use #define macros for this, which reduces the size of such copied code, but doesn't eliminate the problem that it has to be copied in the first place, (and subsequently maintained!). These kind of user definable attributes partially solve that problem, because you can declare declarations in blocks to all be the same attribute. Damn! It's getting late! I better rein this in! Sean "Antti Sykäri" <jsykari@gamma.hut.fi> wrote in message news:slrnbk5c5l.4q6.jsykari@pulu.hut.fi... > In article <bhrn8p$251q$1@digitaldaemon.com>, Fabian Giesen wrote: > >> People don't usually go around killing other people, firstly because [ ... ] > > > > This is beside the point of what I'm trying to say. The question is why there is a compelling need for const. I only see an use for const if it's an > > actual guarantee and the compiler can rely on it and act accordingly (put > > all const data into readonly segments, assume that anything declared const > > is really constant for its whole lifetime). > > Point taken. I didn't particularly try to advocate "const" as it is in C++, just wanted to point out that while it might play a role of a vague promise to the compiler, this is not the case for the programmer (and, importantly, maintainer), who enjoys the benefits of increased type information. > > I'm not sure if const is at all needed. Personally I've been a happy user of const ever since I learned C++ and haven't really tried to live without const (with the exception of occasional straying to the Java side). So I'd rather trust the opinions of the more experienced programmers. Meanwhile, let us concentrate for a moment on the meaning of const. > > Conceptually, the const as we know it in C++ offers a read-only access to the object. If we leave basic types and structs out of the picture, and just look at classes, we can implement it by separating the class' interface into read-only interface and the rest. If the class is already accessed via virtual functions (like a proper class should), this doesn't even impose any extra costs. "Const" access to the class can be provided by explicitly returning the read-only interface of the class, and this is in fact what happens when you specify a "const T" in C++: you actually get an object of type T, but can effectively access only the subset of member functions which are explicitly marked "const". > > This is also an issue that needs to be taken into consideration when designing the basic container library for D. > > Java, a blatant mockery of static typing, solves the "const" by providing a view to the container (via java.util.Collections.unmodifiableCollection or similar) which looks exactly like the original, but throws an UnsupportedOperationException when one tries to modify it. No wonder there's a project trying to bring "const" to Java (http://pag.lcs.mit.edu/constjava/). At any case, if the language has no const and someone wants non-writable containers, (and someone definitely will), the library designer must balance between proliferation of const interfaces and the risk of run-time errors. In C++ he could just leave the complication up to the language. > > Oh, and then there are the basic types which are left without any protection. But I suppose one can get away with some kind of boxing. And nobody wants to pass small values by const-qualified pointers anyway, so they are kind of non-issue. > > As a side note, "const" was originally proposed in 1981 and was called "readonly", and there was also "writeonly". (To mirror the properties of r/w bits in the memory controller; possibly memory-mapped hardware registers) The standardization process changed "readonly" to "const" and dropped "writeonly". > > > As for const, that's a software design issue IMHO. If you add const, then make it rigid. Mutables are okay, because those are also part of the interface specification and thus also documented and acceptable. > > So assume that we'd have these kind of strictly constant / rigidly constant / guaranteed to have the same value objects. "immutable" would not be a bad term, IMO, so I'll use it from now on. > > I can distantly see some consequences: > > - compiler could probably do some optimizations better > > - object of type T cannot be assigned to variable of type immutable T; > to produce an immutable T you either have to clone it or have it > be immutable from the beginning > > - there *will* be cases where the programmer wants to cast a T to > immutable T because he simply knows that the object won't change. > Should a simple cast like ((immutable T) t) suffice? > > - there would have to be methods with immutable modifier, which would > comprise the immutable object's interface > > - plus the added complexity of overloading + other stuff that Walter has > used as an argument against const > > All of this would complicate the language somewhat; but probably only after implementing and experimenting you would know whether it would be worth it. > > Are there any languages out there (except the purely functional ones) > with immutable values? > > Now that I think of it, I remember that Daniel Yokomiso wrote an interesting description of const stuff some time ago, let's see... There, I see it's still worth reviewing: http://www.digitalmars.com/drn-bin/wwwnews?D/9962 > > (Daniel: how's Eon doing, by the way?) > > -Antti |
August 20, 2003 Re: c++ style const concept | ||||
---|---|---|---|---|
| ||||
Posted in reply to Scott McCaskill | Scott McCaskill wrote:
> The canonical example of a good/useful const_cast in C++ is to avoid
> duplicate code when you have const and non-const methods that do the same
> thing. Say I have some kind of array-like class in C++:
Why do you need a non-const version at all?
-eye
|
August 20, 2003 Re: c++ style const concept | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ilya Minkov | > Why do you need a non-const version at all?
Because the (class-)const version only returns a const reference.
-fg
|
August 20, 2003 Re: Attributes (was Re: const / immutable (was: C++ style const concept)) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | > I'm a heavy const user, a true believer in it, I'd say. I'm going to throw > out some ideas: I'm also such an user of const... > > How about adding another kind of access specifier, starting with readonly, such that: > > class A > { > private T t; // private data member > readonly public: // readonly section, also public. this section > applies to both rvalues and lvalues of class A > T GetT() { return t; } > readwrite: // go back to readwrite, still public. This section applies > to lvalues > this(in T t_) { t = t_; } > T SetT(T other) { t = other; return this; } > } > > A couple things I can see from the above: > > It adds complexity to initialization. I recommend just ignoring all readonly accessors during a constructor, and maybe in the destructor too, or > in something obviously lvalue such as an assignment operator. > If something is read-only, IMO, assignment should be prohibited by default and if defined by the user, the user will be able only to assign to readwrite members... > You can avoid having to constantly declare member functions const. Just put > it in its own section. This would save the "extra typing" overhead of C++ const quite a bit. > I would even better like that when const is not specified that the function would be const candidate provide that it would have compiled if const was added. And we uses mutable to explictly tell that a member function is not const and cannot be used on const object even if it would have compiled if const was added. Note that for the return value, when a function is not decorated with a modifier the return value would become const if necessary (the compiler would also remember where const was implicitly added to display usefull error message to the user. Note that code that is compiled for a dynamic library, we should either always specify completly modifier (this would prevent accidental changes) or the compiler should remember the possibilities... Or we could have a keyword for automatic constness (autoconst) that would allows the compiler to decide... > readonly and readwrite are a different set of attribute modifiers, totally separate from private public and protected. Orthogonal to. Unrelated. So > readonly sections can overlap public/private sections, or be overlapped by them. readonly and readwrite might belong in the same category as mutable. > We could also have some more specifier that would be usefull (static, prohibited, published, exported, designtime, runtime, debug, final., inline, unline..) - static would make member static - prohibited would prevent uses (from everywhere - related to access) - published is public and visible by browsing tool (may be related to access) - exported would ensure the item is exported in a dynamic library (DLL) - designtime, runtime would indicate a property available for design or execution, - final would make methods non-virtual -... > Public, private, protected control the visibility of names to everything outside the class. readonly and readwrite control how the class sees itself > (readonly interface, or readonly + readwrite interface) in those member functions, and controls assignability of fields. in, out, and inout control > readwrite access to parameters of those functions, and const declares individual data rvalues, which aren't even castable to anything with write access. That's a lot of names for one basic concept (readonly-ness), so perhaps it could all just be called const, or (lack of const) since the usage situation would already make it unambiguous what you meant. > > This readonly, for the builtin datatypes, and fundamentally, removes the ability to use the assignment operator on such values, or call anything else > that's a readwrite member function, on that type. It should also prevent deletion or other forms of destruction/finalization. And the compiler should be able to treat copies of such a value made during periods in which > it is sure are all protected by that attribute, that they remain identical so long as it knows the readonly attribute is attached to them. When it becomes unsure, it could save and reload it to make sure any changes are reflected, but I'd rather guarantee that nothing will violate the constraint, ever, during the lifetime of the object or data. The compiler should actively prevent the user from modifying such readonly values or allowing them to be modified whenever possible. If that's too restrictive, > use something like mutable, which has different behavior in different situations. > In fact, using some more keywords (or attributes), we would be able to better control what we do... Some keywords that could be usefull are immuable, const, mutable, var(iable), compiletime, byref, byvalue,... Also, as mentionned in this thread, some modifier could be attributes... We would have a bunch of attributes that would give us more control when it is usefull... > I would like to have a kind of constructor that basically allowed the caller > to put whatever values they want into the class's fields, by name: > > this(in); // how would you specify that you want the compiler to > generate a method for you, without having to specify any body? > // By using prototype only, no body, kinda like C++? > It would generate a method for you regardless in C++, but this way you get to control the access. > > I'd use it like so: > > class Point > { > float x,y,z; > this(in); // allow construction with the caller being able to > initialize the public fields and base class more or less directly maybe, we should have a syntax like pure virtual function: this(in) = default; > this(float x_, float y_, float z_) { x = x_, y = y_, z = z_; } // > without that, you have to do this: > } > > new Point a(x:1.0, y:2.0, z:0.0); // call this(in) with initialization for > these members And initialize other to default? If so, this could be nice... > new Point a(1.0, 2.0, 0.0); // initialize fields by calling > this(float,float,float) > > or > > new Point a = { x:1.0; y:2.0, z:0.0 }; // same as this, which I think D allows now? D does named field initialization, right? > Also what would be interesting is an uninitialized keyword so that we can created unitialized object explicitly when performance matters... > Maybe structs just automatically work that way. > > And finally, like C#, I would like to be able to add my own attributes to things. Groups of attributes (private/public/protected would be a group, and so would readonly/readwrite) declared sort of like enums. Unlike anything I've heard of before, you should be able to alias and aggregate these attributes together (a global "alias private readonly notevenIcantouchit;" or "alias public mutable youcanlookbutyoucanttouch"). If you could hook a couple prologue/epilog functions (inlined before and after every function body) to these attributes, then use them to control code generation the same way that contracts work now. > I really like this one too... and it would be even more interesting if some attributes can be different for debug/release, design/runtime,... so that for example, we can have debug functions that are not available in release version (for implementation, it might be a "pure virtual function called" when not available or something like that so that it would be easier to handled partial recompilations... > Even better, you could use such attributes to *implement* things like contracts. > > Think about it. What if you declared something akin to an in and out contract yourself? > > attribute in_custom in { print("in"); assert(this->good()); } > attribute out_custom out { print("out"); assert(this->good()); } > alias attribute in_custom out_custom invariant_custom; > > class Sign > { > invariant_custom: > private int x; > public this() { x = 0; } > bit good() { return x >= 0 && x <= 10; } > void badfunction() { ++x; badfunction(); } // will recurse 10 times > and then trigger an assert exception! > } > > The compiler would inject the attribute code into each function declared after it > > class Foo > { > attribute { > my_read assign { assert(false && "don't assign to my_read objects, > dumbass!"); } > default my_readwrite { } > }; > // everything up to this point is my_readwrite because it's the > default! > my_read int x; // if you try to assign this, you'll assert! > my_readwrite: > // everything else goes here > } > I would then like to ba able to associate atributes also to classes and parameters... A great thing that may be possible is to implement a tracing facilities that would output all functions that are called with the value of their parameters.... I think this is possible with .NET... We just need to be able to get all parameters type and value... > So there are a bunch of basic "kinds" of modifiers such as in, out, invariant, assign, destroy, copy, create, that sort of thing. To control what situations the code attached to the attribute would apply in. Also these attributes shouldn't run until the constructor for the object has finished, and shouldn't run once the finalizer starts. That way it's guaranteed to have a complete object to deal with. > > I don't think it would be a good idea to allow decorating member variables with code. Or would it? A member variable or data attribute would control > things like assignment, reference, and might serve as an easy way to do properties with a write-through or read-only data field. (The properties in > the D spec now may never see the light of day!) > > Maybe there should be some kind of compile time error for when the compiler > can detect at compile time that a code path is going to definitely be executed that contains an assert statement (such as the assign assert above) > and issue a compile time error. > I would suggest a keyword (or predefined special function) that would be used instead of assert in such cases... And also one for functions that are not yet implemented or code that is not completed (todo, bug, ...) maybe compile_time_state(a) where a is an identifier and we can tell the compiler which identifier are ignored, which one causes a run-time error and which causes a compilation error. > I guess all this adds to the complexity of the compiler. That's a good thing, in some ways. This could be powerful stuff in the right hands. Maybe could be combined with templates somehow? > I don't the relashion with template... but it may indeed be interesting to be able to do some metaprogramming based on those attributes. > It's really just the ability to add custom extra type information to your types. > > One of the major costs of maintenance is having code cut-and-pasted in a bunch of places, as it is hard to change something if it's scattered all over the place. With attributes you can write boilerplate code and attach it to things with an attribute in its declaration. This is good because it > keeps such code in one place, in the attribute definition, rather than cut and pasted into every copy of every function that needs it. In C / C++ you > have to use #define macros for this, which reduces the size of such copied code, but doesn't eliminate the problem that it has to be copied in the first place, (and subsequently maintained!). These kind of user definable attributes partially solve that problem, because you can declare declarations in blocks to all be the same attribute. > > Damn! It's getting late! I better rein this in! > > Sean > > > I would like that the compiler would have a mode in which it case do some extended analysis of the code and potential pitfalls... |
August 21, 2003 Re: c++ style const concept | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ilya Minkov | "Ilya Minkov" <midiclub@8ung.at> wrote in message news:bhvj1j$1o2o$1@digitaldaemon.com... > Scott McCaskill wrote: > > The canonical example of a good/useful const_cast in C++ is to avoid duplicate code when you have const and non-const methods that do the same > > thing. Say I have some kind of array-like class in C++: > > Why do you need a non-const version at all? > So I can write this: // given: MyArray& a a[0] = 5; -- Scott McCaskill |
August 21, 2003 Re: Attributes (was Re: const / immutable (was: C++ style const concept)) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Mori | "Philippe Mori" <philippe_mori@hotmail.com> wrote in message news:bi0eoa$2uk4$1@digitaldaemon.com... > > It adds complexity to initialization. I recommend just ignoring all readonly accessors during a constructor, and maybe in the destructor too, > > or in something obviously lvalue such as an assignment operator. > > > > If something is read-only, IMO, assignment should be prohibited by default and if defined by the user, the user will be able only to assign to readwrite members... Hmm. Anything that's not writable has to be initialized explicitly, which causes some order of construction issues, especially if field initializers reference other fields' values. > > You can avoid having to constantly declare member functions const. Just > put > > it in its own section. This would save the "extra typing" overhead of C++ > > const quite a bit. > > > > I would even better like that when const is not specified that the function > would be const candidate provide that it would have compiled if const was added. And we uses mutable to explictly tell that a member function is not const and cannot be used on const object even if it would have compiled if const was added. This is just making it easier for people to be lazy. ;) > Note that for the return value, when a function is not decorated with a > modifier > the return value would become const if necessary (the compiler would also > remember where const was implicitly added to display usefull error message > to the user. It should be easy to add modifiers to a piece of data and hard/impossible to take them away (without making a new copy of the data/object) > Note that code that is compiled for a dynamic library, we should either always specify completly modifier (this would prevent accidental changes) or the compiler should remember the possibilities... I haven't thought it through that far. Not concerned with DLL's at this stage. ;) > Or we could have a keyword for automatic constness (autoconst) that would allows the compiler to decide... Hmm. People would forget the autoconst keyword. ;) > We could also have some more specifier that would be usefull (static, prohibited, published, exported, designtime, runtime, debug, final., inline, > unline..) > > - static would make member static > - prohibited would prevent uses (from everywhere - related to access) > - published is public and visible by browsing tool (may be related to > access) > - exported would ensure the item is exported in a dynamic library (DLL) > - designtime, runtime would indicate a property available for design or > execution, > - final would make methods non-virtual > -... Sure, we could think of lots of predefined ones. It's talking Walter into them that's hard. ;) > In fact, using some more keywords (or attributes), we would be able to > better control what we do... Some keywords that could be usefull > are immuable, const, mutable, var(iable), compiletime, byref, byvalue,... People keep writing "immuable" when in fact the English word for that is "immutable". Dictionary.com says: No entry found for immuable. Did you mean immutable? > Also, as mentionned in this thread, some modifier could be attributes... We would have a bunch of attributes that would give us more control when it is usefull... People always want more control, and attributes would be so much better than command line switches. Makes the code self-documenting, self-directing, and removes the need for dealing with the compiler from the command line. > > class Point > > { > > float x,y,z; > > this(in); // allow construction with the caller being able to > > initialize the public fields and base class more or less directly > > maybe, we should have a syntax like pure virtual function: > > this(in) = default; I never liked that syntax. I'd rather have the default in front, so it can be an attribute too! > > new Point a(x:1.0, y:2.0, z:0.0); // call this(in) with initialization > for > > these members > > And initialize other to default? If so, this could be nice... Yes, unspecified fields would get their type's default, or whatever the class initializes them to by default. > Also what would be interesting is an uninitialized keyword so that we can created unitialized object explicitly when performance matters... Maybe you can't create uninitialized object that's derived from some other object (the bases will get initialized anyway) and if you call a constructor it has to get initialized. More of a declaration on a piece of data that says "I'm making a new object but don't want it initialized, and will not need to call any constructor". Basically just wraps allocation and typecasting. You could attribute member variables with this. Or any stack data. Maybe not classes. > I really like this one too... and it would be even more interesting if > some attributes can be different for debug/release, design/runtime,... > so that for example, we can have debug functions that are not > available in release version (for implementation, it might be a "pure > virtual function called" when not available or something like that > so that it would be easier to handled partial recompilations... I never considered partial recompilation. Seems like everything that needs to be recompiled should be. > I would then like to ba able to associate atributes also to classes and parameters... Yes. To anything. Data, member functions, entire classes or structures or any type. > A great thing that may be possible is to implement a tracing facilities that would output all functions that are called with the value of their parameters.... > > I think this is possible with .NET... We just need to be able to get all parameters type and value... That'd be handy sometimes. > I would suggest a keyword (or predefined special function) that would be used instead of assert in such cases... Good idea. Maybe a few variants on assert. assert is just shorthand for debug { if (x) throw AssertException; } Maybe one that throws a string message, or throws a message box to be executed... and one that throws nothing at all, just effectively a breakpoint. A debugger catches it and if there's no debugger, or in release builds, it just goes on past. That's something I always put in my libraries of code, a call to cause a breakpoint. Use that to build assert macros. Seems like a debugging feature (aka BASIC's stop command) which could be really useful. > And also one for functions that are not yet implemented or code that is not > completed (todo, bug, ...) Yeah, their code could print messages to the build log with line numbers etc. > maybe compile_time_state(a) where a is an identifier and we can tell the compiler which identifier are ignored, which one causes a run-time error and > which causes a compilation error. Switches like this are already handled with version statements; if we can define attributes differently depending on version, we're good to go. > > I guess all this adds to the complexity of the compiler. That's a good thing, in some ways. This could be powerful stuff in the right hands. Maybe could be combined with templates somehow? > > I don't the relashion with template... but it may indeed be interesting to be able to do some metaprogramming based on those attributes. I'm not sure. Haven't thought about that enough. > I would like that the compiler would have a mode in which it case do some extended analysis of the code and potential pitfalls... Pedantic. ;) lint mode. Sean |
August 23, 2003 Re: const / immutable (was: C++ style const concept) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Mori | In article <bhug4k$78v$1@digitaldaemon.com>, Philippe Mori wrote: >> > As for const, that's a software design issue IMHO. If you add const, then make it rigid. Mutables are okay, because those are also part of the interface specification and thus also documented and acceptable. >> >> So assume that we'd have these kind of strictly constant / rigidly constant / guaranteed to have the same value objects. "immutable" would not be a bad term, IMO, so I'll use it from now on. >> >> I can distantly see some consequences: >> >> - compiler could probably do some optimizations better >> >> - object of type T cannot be assigned to variable of type immutable T; >> to produce an immutable T you either have to clone it or have it >> be immutable from the beginning > > So your definition of immuable that an object won't changes... but for a function parameter, does it apply to both the source and target or only to the target (as const in C++). What do you mean by source and target in this context? Immutable's just an object that will never change after it has been initialized. >> - there *will* be cases where the programmer wants to cast a T to >> immutable T because he simply knows that the object won't change. >> Should a simple cast like ((immutable T) t) suffice? >> >> - there would have to be methods with immutable modifier, which would >> comprise the immutable object's interface >> >> - plus the added complexity of overloading + other stuff that Walter has >> used as an argument against const > > For overloadding, we should then have a way to reuse the same code for all variations if applicable. > > typical case would be to be able to select the appropriate constness of the return value of a member function... > > I think that the compiler could automatically make the result const if this is required (for ex. when returning an element from a const container). > > class E; > > class C { > E &get() { return member; } > > E member; > } > > Here if get is called on a const C, the compiler could add const to E if otherwise the function would compile if it were const. > > Doing it that way would avoid most of the complexity of overloadding in C++ where we need to provide both a const and a regular version of the same function. > > Also, the programmer won't be required to put all const... The compiler would be able to do some analysis to verify if a function can be generated. Can you elaborate your ideas a bit? I'd be interested to see an example which would show that your idea works in practice. IMO, Autogenerating methods at compile-time where "const" needed seems complex and it might cause some overhead. For example, class interfaces would need to have const version for each method. For example, what if your example was derived for an interface: class C; interface C_Interface { E get(); // Compiler must autogenerate this in order to any derived C to work:: const E get() const; } class C : C_Interface { E get() { return member; } // Compiler needs to generate E get() { return member; } E member; } class C2 : C_Interface { E get() { return new E(); } // This one will always non-const E always, but how does the client // know that if it accesses a C_Interface object? // Back to the drawing board - need to add "E get() const;" function // to C_Interface. Too much bloat } > And with prohibited keyword that I suggest in another thread, one would be > able to prohibit using the const version if he wants (for example for a swap > function, we don't want const parameter and prohibiting it would do > that the compiler won't have to continue analysis...) I still don't see much use for the "prohibit" keyword. It would mostly be useful if the compiler would auto-generate a lof of functions (such as copy constructors, assignment operators in C++) and there would be a need for not having them. > prohibited would be a function modifier that will ensure that the function is never called. Then why put the function there in the first place? :) -A |
August 24, 2003 Re: const / immutable (was: C++ style const concept) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Antti Sykäri | > > > > So your definition of immuable that an object won't changes... but for a function parameter, does it apply to both the source and target or only to the target (as const in C++). > > What do you mean by source and target in this context? > Immutable's just an object that will never change after it has been > initialized. > Suppose something similar to this: void f(int &target) { ... } int source = 1; f(source); The source is from where the data come... Can source be modified externally (other thread, alias, while f is executing. Target is what we do inside the function... Maybe not the best terms... It is the perspective from either side (i.e. inside the function, can I assumes that the received object is constant and do some optimisation in consequence, does I have the possibility to modify the source object (possibly with a cast, or the object is really const (unmodifiable) or a copy.... So one might like to tell that the source cannot change (even externally) and another one might tell that target won't change... > > > > I think that the compiler could automatically make the result const if this is required (for ex. when returning an element from a const container). > > > > Also, the programmer won't be required to put all const... The compiler would be able to do some analysis to verify if a function can be generated. > > Can you elaborate your ideas a bit? I'd be interested to see an example which would show that your idea works in practice. IMO, Autogenerating methods at compile-time where "const" needed seems complex and it might cause some overhead. For example, class interfaces would need to have const version for each method. For example, what if your example was derived for an interface: > OK, I see my error... Essentially, it would only be possible to do such analysis for final method.... For all other method, it does not works well. In fact, const is most appropriate for concrete (final) and simple type that can be checked at compile-time... and maybe we should support const only for those types (so that for ex. if we pass a constant container (that would be a concrete type), we would be able to prevent modification to the container... This also means that for templates like a container, we want a concrete class that is final (no possible override)... > > > And with prohibited keyword that I suggest in another thread, one would be > > able to prohibit using the const version if he wants (for example for a swap > > function, we don't want const parameter and prohibiting it would do that the compiler won't have to continue analysis...) > > I still don't see much use for the "prohibit" keyword. It would mostly be useful if the compiler would auto-generate a lof of functions (such as copy constructors, assignment operators in C++) and there would be a need for not having them. > > > prohibited would be a function modifier that will ensure that the function > > is never called. > > Then why put the function there in the first place? :) > I see a few cases: - The functions is implictly generated - There are some implicit conversion that are allowed but does not give the desired result (for ex. in C++ std::string class can be initialized from 0.0 or false because of implicit conversion that occurs but are not desirable in that specific context). In practice, if we find such a bug, then we have an easy way to ensure we won't have it another time. - One existing function become obsolete and we want to ensure that it is not used anymore but because there are other similar overload we like the compiler to trap them and issue an error. A keyword allows to make it clearer... Otherwise it is possible to do it with templates but it is more complicated... - In generic (template) code, we might know some undesired types for arguments (like swapping one constant object or swapping objects of distincts type). If we have a prohibited keyword, it is a lot easier to prohibit what we don't want that to make code that would causes a compilation error in those cases... I have done it (preventing code from compiling) a lot of times in C++ when I was refactoring the code that have known problems. I was using the compiler to help me find those problematic places... |
August 24, 2003 Re: Attributes (was Re: const / immutable (was: C++ style const concept)) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer |
> >
> > I would even better like that when const is not specified that the
> function
> > would be const candidate provide that it would have compiled if const was added. And we uses mutable to explictly tell that a member function is not const and cannot be used on const object even if it would have compiled if const was added.
>
> This is just making it easier for people to be lazy. ;)
>
As mentionned in my other answer, you are right, it does not works well with virtual functions and since this is the default in D, the if someone can think not to forgot to make classes final when appropriate that people should be able be uses const as appropriate.
So in pratice, constness modifier would be mostly usefull for libraries writers (similar to STL, boost and others...) but not that much for user.
What do you think about allwing const only for final class type and simple types (integral, enum, struct, pointers) and not allows it on other types.
And there would be a way to share code between a const and non-const version of the sane thing (constnessof would be a good keyword for that - it would allows to modifiy the constness of a type (including function return value) from the constness of another one or more)
|
Copyright © 1999-2021 by the D Language Foundation