December 03, 2002 Re: in,out,inout: new sematic proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert W. Cunningham | Robert W. Cunningham wrote:
> A systems programming language (SPL) requires two fundamental features
> of its type system in order to meet any minimal definition of being an
> SPL: 'const' and 'volatile' (or equivalent). Even Ada has them, in
> very constrained but still VERY useful forms.
>
> "Const" (and 'volatile', while we're at it) does not have to have
> universal applicability in order to be valuable and useful. "Sloppy"
> use of const should not be encouraged, and shouldn't be tolerated when
> detected. In my C code, I find using "gcc -Wall" helps quite a bit.
First off, I'm in the C++ const is bad camp. It has too many variant meanings, and as Walter has said, it doesn't really prevent all that many bugs, IMO. const, as it stands now in D, is fine with me. It means constant, and cannot be changed at runtime. It's a binding contract, which is what const should be. The only think that I would add, if it's possible, is to add const type functions, although with another keyword. Basically, it would be another contract, with no passed in variables, pointers, or references being changeable in the body of that particular function. Anything not in the local scope being assigned a value of any kind would be an error. I don't know if this is possible, from a compiler writer's standpoint, but of all the variant meanings of const, this is the only one that I would support adding to D. Like I said, I don't know about the keyword (other than it needs to be called something other than const) but I'm sure that we can come up with something that fits the semantics well.
Evan
|
December 15, 2002 Re: in,out,inout: new sematic proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert W. Cunningham | "Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3DEC11FC.DB684E1C@users.sourceforge.net... > Has anyone tried to write a device driver in D? How about a small OS (or a port of uCOS) that boots itself? Those are the kids of things Systems Programming Languages are created for. I don't think they can be done in D without lots of work-arounds in assembler that C doesn't need: D doesn't play nice with hardware, especially when the processor has a cache. Ergo, (IMHO) D is not (yet) a systems programming language. I am intimately familiar with how C compilers generate code, with and without const and volatile. There just isn't much to be gained with it, and a lot of trouble is caused by it. D, however, does support the const as a storage class, as in: const foo = 3; D also supports the volatile statement, which prevents caching of values across the statement boundaries. The combination of this, the const storage class, and the ability to access arbitrary addresses with pointers, I think fills the bill. D also has, unlike C or C++, a defined interface to assembler. Take a look at the linux kernel source, it is full of random bits of assembler. That doesn't mean that C isn't a systems programming language. What it does mean is that the awful gnuc inline assembler leaves a lot of room for improvement, which D does. > Walter, all your points AGAINST const are valid! Just because you know of many misuses for and difficulties with 'const' doesn't mean there still aren't many VALID needs and uses for const and volatile. Just because you haven't encountered them and can't envision them does not mean they don't exist. It only means I suck at explaining them. I wish I could craft a better argument, or provide the needed insight and education. Despite several tries, I have failed miserably to convince you. I do respect your opinion on this, and I have been equally hard at work trying to convince you otherwise! > Or you can simply TRUST ME that some minimal form of 'const' and 'volatile' are mandatory for systems programming, and add them to the D language specification. They are there in the (minimal) form mentioned earlier. And yes, I have written device drivers in both C and assembler. |
December 16, 2002 Re: in,out,inout: new sematic proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert W. Cunningham | Robert W. Cunningham wrote:
> A systems programming language (SPL) requires two fundamental features
> of its type system in order to meet any minimal definition of being an
> SPL: 'const' and 'volatile' (or equivalent). Even Ada has them, in
> very constrained but still VERY useful forms.
Assembly language doesn't have 'const' or anything equivalent. So how can you say it is required or a system programming language?
As for volatile, that only impacts optimization techniques. Since assembly language programs are normally not optimized by the assembler, volatile is not needed. Likewise, you can turn off all optimizations in a compiler and thus volatile won't be necessary there, either.
Thus, neither is actually necessary. IMHO, Walter's design, while not perfect, is an incremental advance over C/C++. It allows us to use volatile statements to read & write things, but gives us more optimization than C allowed.
|
January 14, 2003 Re: in,out,inout: new sematic proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | "Walter" <walter@digitalmars.com> wrote in news:asccu1$h8l$1@digitaldaemon.com: > 5) Const as a type modifier permeates the type system, and has effects spilling all over places it has no business doing so. For example, it affects the partial specialization rules of templates, not in any clarifying way, but just adding more layers of complexity and special case rules. I have a simple question about current C++/D compiler implementations, just to assure that I'm on the right way: Would it make the D compiler implementation easier if D treated "const someRefType" as the imaginary base-type of the type "someRefTyp" ? All rules for overloading, type compatibilty, partial template specialization, etc. that are used for inherited types are simply applied to const. Sure, the type hierarchy of const is a bit special: example: class Base {} class Child : Base {} now the imaginary inheritance tree would be: a)"const Child" inherits "const Base". but b)Child inherits "const Child" inherits Base inherits "const Base". I suppose that you can deduce most rules of C++ regarding const with this simple notion. One exception I know of, are the partial specialization rules of C++ templates. But these rules look counter-intuitive and are often useless. The rules deduced from my notion of const do not look worse than those of C++ to me. Maybe they are even better. Could anyone provide an example that proves that my simple notion of const cannot fit the bill ? Farmer |
January 15, 2003 Re: in,out,inout: new sematic proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Farmer | "Farmer" <itsFarmer.@freenet.de> escreveu na mensagem news:Xns9303EEFE9D5FitsFarmer@63.105.9.61... > "Walter" <walter@digitalmars.com> wrote in news:asccu1$h8l$1@digitaldaemon.com: > > > 5) Const as a type modifier permeates the type system, and has effects spilling all over places it has no business doing so. For example, it affects the partial specialization rules of templates, not in any clarifying way, but just adding more layers of complexity and special case rules. > > > I have a simple question about current C++/D compiler implementations, just > to assure that I'm on the right way: > > Would it make the D compiler implementation easier if D treated "const someRefType" as the imaginary base-type of the type "someRefTyp" ? > > All rules for overloading, type compatibilty, partial template specialization, etc. that are used for inherited types are simply applied to const. > > Sure, the type hierarchy of const is a bit special: > > example: > > class Base > {} > > class Child : Base > {} > > now the imaginary inheritance tree would be: > > a)"const Child" inherits "const Base". > but > b)Child inherits "const Child" inherits Base inherits "const Base". > > > > I suppose that you can deduce most rules of C++ regarding const with this simple notion. > > One exception I know of, are the partial specialization rules of C++ templates. But these rules look counter-intuitive and are often useless. The rules deduced from my notion of const do not look worse than those of C++ to me. Maybe they are even better. > > Could anyone provide an example that proves that my simple notion of const cannot fit the bill ? > > > Farmer > Hi, This subject is one of those continuous discussions on Usenet. comp.lang.eiffel has some posts talking about this, regarding CQS (command/query separation) and lots of people talked about it. Here's my thoughts about it. There are two views of what "const" means when applied to types: (1) this is constant and will never change; or (2) this is mutable but YOU can't change. Each gives a whole different world to the compiler and to the programmer. Also there's const applied to functions, both with two different views: (A) this function is a pure function, you can use equational reasoning about it; or (B) this function won't change any of it's parameters (including implicit this for methods), or that's what I want you to think. When you create a const ancestor type to any type, you want it to mean both const for type (either 1 or 2) with interfaces defined for the type's const functions (either A or B). These four possible combinations can give us lots of headache. So let's think about them: (1A) this means functional objects, that is objects with value semantics. Structs aren't true value objects but C/C++ folk usually talk about them being so. Anyway you could define: class Color { const Color darker(); const Color lighter(); const int alpha(); const int red(); const int green(); const int blue(); const float hue(); const float saturation(); const float brightness(); const char[] toString() void printOn(OutputStream out) } and a type const Color would be defined with all these methods in it. Note that const in the methods applies to the method, not to the result type, so char[] from toString() is mutable and Color from darker() and lighter() too, not that it means something. But it gives you two functions that map const Color domain to Color domain. (1B) this is similar to 1A, but includes trick functions. In the same Color class we could define this: class Color { // same as before const int cyan(); const int magenta(); const int yellow(); const int black(); } The four new methods are const, but inside their definitions they break the rules lazily caching the values so multiple uses won't result in multiple computations. All cache mechanisms for pure-functions must "cast away the constness". (2A) Useful for restricting user's access to mutable methods of types. class Car { const void lookAt(); const void wash(); void drive(); void crash(); } class SomeoneElse { void driveInto(Car target); } abstract class Driver { abstract (const Car) lendCarTo(const Driver any); abstract Car lendCarTo(const GoodDriver good); } class LameDriver : Driver { } class GoodDriver : Driver { } I think it's valid overloading. The GoodDriver class can access a more complete version of Car, because it will never call the mutable method crash(), but needs to use drive(). LameDriver's skills stop him from doing anything besides lookAt() and wash(). But while LameDriver lookAt() theCar SomeoneElse can driveInto(theCar) and crash it anyways, because they can mutate it. It's the same problem with collections and immutable interfaces, or using iterators while another thread changes the collection. (2B) Similar to 2A, but in this case drive() could be also declared const and secretly update the gas tank during all method calls. Each combination has it's strengths and weaknesses, now let's see how could we implement this mess of semantics in D: (1A) give a const modifier to classes and functions. It's similar to Sather immutable objects. It will help people define better semantics for their types (a Date class could be const, like it should be, not like some other OO languages do ;-) ). (1B) It's 1A plus a cast to allow secret mutations. Walter will love it ;-) (2A) give more things to the compiler play with. It's also a fun thing to toy with: slice operations give const type or type? Current D's array semantics (very pragmatic) use COA (like COW but appending instead of writing), so "type [index] = value" should be a operation of const type, but "type ~= value" should be a operation of type. (2B) more fun than 2B, after all you can always cast the constness away to make things weirder. AFAICS this is that const means lots of things, and each of these things is different from the others. We should think very carefully before changing any type system semantics with such huge change. No imperative language currently has this (and IIRC not hibrid language too). Best regards, Daniel Yokomiso. P.S.: When I implement my pet language, Eon, I'll give it immutable types and values, but it's goals and type system are different from D's. I'm entering on the second year of study to create it's type system (hundreds of papers read) and in the meantime I put and dropped immutable types several times. If someone is interested I plan to provide both 1A and 2A, but throught two different mechanisms. "Chaos! Panic! Disaster! (My work here is done)." --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.435 / Virus Database: 244 - Release Date: 30/12/2002 |
January 19, 2003 Re: in,out,inout: new sematic proposal | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Yokomiso | Hi, my question "Could anyone provide an example that proves that my simple notion of const cannot fit the bill ?" should read: "Are all those complicated rules of C++ regarding "const", really necessary. Please show me examples, where my simple notion of const (mapping the const attribute to a class hierarchy), would not work in C++ or in D". By "const", I primarily think of "const" applied to class methods in C++. now my comments on your post: I think the 2B meaning of constness is most useful for D programmers. >(2) this is mutable but YOU can't change. >(B) this function won't change any of it's parameters (including > implicit this for methods), or that's what I want you to think. Equational reasoning is not a concern for most D programmers. They usually think that functions do some work like I/O operations. The meaning >(1) this is constant and will never change; is too limiting for most cases. Of course there could be uses: e.g. java.lang.String > abstract class Driver { > abstract (const Car) lendCarTo(const Driver any); > abstract Car lendCarTo(const GoodDriver good); > } I guess, you wanted to write abstract class Driver { abstract (const Car) lendCarTo(Driver any); abstract Car lendCarTo(GoodDriver good); } since the state of both Driver and GoodDriver instance will change. (now they have access to a car) > I think it's valid overloading. The GoodDriver class can access a more > complete version of Car, because it will never call the mutable method > crash(), but needs to use drive(). LameDriver's skills stop him from > doing anything besides lookAt() and wash(). But while LameDriver > lookAt() theCar SomeoneElse can driveInto(theCar) and crash it > anyways, because they can mutate it. It's the same problem with > collections and immutable interfaces, or using iterators while another > thread changes the collection. Right. But that is exactly the meaning that should be expressed by constness: You prevented the LameDriver from crashing your car. But a tornado still can do that (You cannot prevent that in real life ->a compiler can't do either). You need to design an indestructable car to get an immutable Car class. > (2A) give more things to the compiler play with. It's also a fun thing to toy with: slice operations give const type or type? Current D's array semantics (very pragmatic) use COA (like COW but appending instead of writing), so "type [index] = value" should be a operation of const type, but "type ~= value" should be a operation of type. (2B) more fun than 2B, after all you can always cast the constness away to make things weirder. My knowledge about pure functions are non existent, so I'm surely missed some fun. Why should "type [index] = value" be an operation of const ? According to my simple rules for const. You could only get a "const slice" from a "const slice". But from a "nonconst slice" you can get both version. > AFAICS this is that const means lots of things, and each of these > things > is different from the others. We should think very carefully before > changing any type system semantics with such huge change. That's why I'm asking Walter whether it is possible to reduce the complexity of constness (for both compiler writers and programmers) in first placen, BEFORE I'm trying to work out a proposal to introduce const to D. And I think, it's likely to be impossible to introduce const to D's type system. The type system is already complex hardly any support for constness. Well, I have some thoughts about const, too: I feel that the following notions of constness could be useful to a programming language like D. typical keywords: meaning 1)const (D): compile time constants; no memory is allocated for these constants. 2)readonly (C#), final (Java): variable that cannot be changed after it has been initialized. 3)const (C++ in context of methods): logical (not necessarily bitwise) constness of UDT's, meaning that the object state cannot be change using this variable identifier. 4)__romable, const (Ansi C99 ?): variable can be stored in ROM-memory; its value will never change. [I don't need that, but maybe some embedded systems programmers will love it.] 5)__callconst: this attribute can only be applied to non-const arguments of functions. It should mean that the argument is not changed within the function. But the argument is usually stored in a global variable (or member variable ). This constness could be useful for container classes: E.g. a stack stores an non-const object with the push() method. This method does not change the object. Though, this method cannot take an const argument, because you want to get a non-const object back from the stack with the pop() method. Unfortunately I, see no solution for a D-compiler to enforce this behaviour -> this keyword could only be syntax sugar for writting self-documenting code. Of course, one could hack the language to catch at least the most obvious violations of "__callconst". Do you know of any language, that can express constness as required for container classes ? Farmer. |
March 09, 2003 volatile | ||||
---|---|---|---|---|
| ||||
Posted in reply to Russell Lewis | Russell Lewis <spamhole-2001-07-16@deming-os.org> Wrote: >As for volatile, that only impacts optimization techniques. Well, in C, volatile is usefull when I have a variable that is a representation of an I/O port that is connected to some hardware you're monitoring. For instance, say your program is deciding something based on the state of a sensor. Because you never know when the state of the port will change, you'll have to use volatile to force the program to really check the port, otherwise you're (maybe/probable) hitting an old cached value, and get wrong results. How does D solve that? |
March 09, 2003 Re: volatile | ||||
---|---|---|---|---|
| ||||
Posted in reply to Pedro Alves | "Pedro Alves" <Pedro_member@pathlink.com> wrote in message news:b4f1eo$1dd9$1@digitaldaemon.com... > Russell Lewis <spamhole-2001-07-16@deming-os.org> Wrote: > >As for volatile, that only impacts optimization techniques. > > Well, in C, volatile is usefull when I have a variable that is a representation > of an I/O port that is connected to some hardware you're monitoring. For instance, say your program is deciding something based on the state of a sensor. > Because you never know when the state of the port will change, you'll have to > use volatile to force the program to really check the port, otherwise you're > (maybe/probable) hitting an old cached value, and get wrong results. > How does D solve that? > volatile ! http://www.digitalmars.com/d/statement.html#volatile |
Copyright © 1999-2021 by the D Language Foundation