www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why I (Still) Won't Use D

reply Benji Smith <benji benjismith.net> writes:
I first stumbled across the D programming language way back in 2002.

For a few years, I was active in all of the newsgroup discussions, and I 
spent a significant proportion of my spare time tinkering with D library 
development (I actually wrote an XML parser in D back in early 2003).

At that time, Phobos was still pretty slim (and there was no Tango), so 
the language didn't have a standard library that could really support 
application development. And there was no support for D in IDEs or 
debuggers.

And there were a few pesky language issues that irked me (no boolean or 
string types, for example), and a fair handful of compiler bugs that 
needed to be fixed.

But the language was *ALMOST* ready.

And I was excited for a syntactically simple, 
semantically-straightforward development language that compiled to 
native machine code. On windows, linux, or mac!! Hooray!

Although my active participation in the community evaporated when my 
kids were born (premie twins who spent 4 months in the ICU with a 
laundry-list of complications), I've continued to regularly lurk here 
for the last six years.

Over that time, the tools and infrastructure surrounding D have improved 
vastly. Tango is a spectacular piece of work. DSource is very 
impressive. The available libraries are maturing nicely. The compilers 
are much more robust. Lots of things about D are looking very compelling.

There's a new project on my plate right now. I need to produce native 
binaries, with C bindings. It needs to run on win/linux/mac. And it 
needs to be small and lightweight (though not necessarily blazingly fast).

It seemed like the perfect opportunity to give D another shot.

So I dove back in and read through the docs, and I've been reading 
*everything* on the NG for the last month or so. I've been reading 
tutorials and browsing through code repositories.

And, I'm sorry to say, the language itself has seriously degraded, even 
while the libraries and tools have improved so much.

It's very disheartening.

Here are some of the things that are most offputting:

CONST

Const is a total trainwreck, and is the biggest reason for me to stay 
away from D in a real project. Even now, nearly a year after the 
introduction of const/final/invariant, there are still NG threads with 
more than a hundred posts with people trying to understand how const is 
supposed to work and how they can accomplish (really simple) goals under 
the current const regime.

Before the advent of the various const implementations, I could glance 
at a function declaration and know exactly what it meant. Now it takes 
much more effort to understand even the most const-aware functions and 
develop a strategy for working with them in an application.

Even if I liked the current semantics, everything still seems so 
up-in-the-air with const, I'd be loathe to dive in until it stabilized. 
And I don't see that happening anytime soon.

It seems like most of the people weighing in on the const debate are 
trying to figure out a type system and a set of operations that will 
support all possible use cases. (Like the recent "const debacle" thread.)

It seems like const will either become too complex for ordinary usage 
(and will be worked-around more often than used properly) or it will 
become too weak to be enforce absolute safety/optimization guarantees.

Personally, I'd rather have no concept of const at all than adopt any of 
the implementations that have been proposed so far.

STRINGS

The existence of three different string types (six, if you count 
const/mutable variations of each) makes text-processing more difficult 
than it ought to be.

I would have liked to see just one string type, with encoding kept as an 
internal implementation detail. And I'd much rather have a string class 
than to treat strings as character arrays (especially since 
indexing/slicing deals with code-points rather than character positions).

KEYWORD OVERLOAD

The mandate to keep keyword count as low as possible has been a real 
detriment to the language.

Each unique concept should have its own unique keyword.

As I've been trying to learn the language, it's easy to get confused 
when a keyword takes on multiple different meanings, depending on its 
context. For example, although I've kept casually following this NG for 
all this time, I've never fully grokked all the different meanings of 
"static".

ARRAYS

1) There's a gap in functionality between static arrays (whose size must 
be known at compile time) and growable dynamic arrays.

Most often, what I really want is a non-growable array whose size isn't 
known until runtime, but D doesn't have that concept (Java and .NET have 
it). And the disparity between the static & dynamic array types (which 
are fundamentally different in the type system) means I can't write code 
like this:

   int[] doSomething(int[] array) { ... }

   int[4] a;
   int[] b;

   // Inplicit conversion. Does this copy data?
   b = doSomething(a);

   // Error: functions can't return fixed-length arrays!
   a = doSomething(b);

That's really too bad. The type system really should treat an int[] and 
an int[4] as the same type. If the compiler wants to optimize certain 
static arrays by putting them in the data section of the compiled OBJ, 
when possible, that's fine by me. But having that behavior affect the 
type system is a pain in the neck.

I also would have preferred to have growable arrays and associative 
arrays in the standard library than in the language. A more unified 
array syntax could get rid of some nasty warts like this:

   // Doesn't compile
   char[][] words = [ "hello", "world" ];

   // Compiles, but the only way to know about this trick is by asking
   // someone for help in the NG.
   char[][] words = [ "hello"[], "world" ];

   // Would be ideal. Growable arrays would be best implemented as a
   // templatized collection class.
   List!(String) words = [ "hello, "world" ];

2) An empty array is equal to a null pointer. Yikes!

3) Array syntax should support both multi-dimensional arrays and jagged 
arrays:

   int[,] multidim = new int[4,5];
   int[][] jagged = new int[4][5];

ANYHOW...

There are lots of other little annoyances, but those are the biggest 
things I can think of right now.

For me, the D language is becoming less and less compelling as time 
passes. I have a hard time wrapping my mind around all the keyword 
ambiguities, let alone the little quirks necessary to keep the compiler 
happy. And the const semantics don't seem anywhere near a resolution.

I feel like, if I'm going to use such a complex language, I may as well 
choose C++, which offers the advantages of ubiquity and language stability.

Nevertheless, the things that keep me interested in D are:

* Multi-platform, compiled to machine code. No VM required.

* No header files.

* No preprocessor.

* Built-in garbage collection.

* Real structs

* Semantic import, rather than lexical #include.

* No need for forward declarations.

* Single inheritance, and interfaces.

But whenever I've come back to give D another look, the weaknesses 
always outweigh the strengths. I don't want to memorize a bunch of 
loopholes. I want a straightforward language that makes sense, right out 
of the box.

(Incidentally, most of my development work over the last few years has 
been in statistical machine learning, vector-space information modeling, 
agent-based simulation, and domain-specific language compilers.)

I know this is a really long message, but I wanted to provide some 
feedback about why -- after all these years -- D is still not an option 
for my development projects. And that's in spite of me really *wanting* 
something that follows the original, core D design principles.

Cheers,

--Benji Smith
Mar 27 2008
next sibling parent "Saaa" <empty needmail.com> writes:
If you would use the stable D1.0 at least Consts wouldn't be a problem. 
Mar 27 2008
prev sibling next sibling parent reply e-t172 <e-t172 akegroup.org> writes:
Benji Smith a écrit :
   // Doesn't compile
   char[][] words = [ "hello", "world" ];

Yes it does: --- module aainit; import tango.io.Console; void main() { char[][] words = [ "hello", "world" ]; foreach (word; words) Cerr(word).newline; } --- $ gdc -o aainit aainit.d $ ./aainit hello world With D 1.0, GDC r199.
Mar 27 2008
parent reply Benji Smith <benji benjismith.net> writes:
e-t172 wrote:
 Benji Smith a écrit :
   // Doesn't compile
   char[][] words = [ "hello", "world" ];

Yes it does:

Huh. Am I confusing that with some other (similar) issue? Of course, if I'm totally out in left-field, then I'm happy to see the resolution of something that was an issue in the past (wasn't it?). --benji
Mar 27 2008
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Benji Smith" <benji benjismith.net> wrote in message 
news:fsgmru$7tk$1 digitalmars.com...
 e-t172 wrote:
 Benji Smith a écrit :
   // Doesn't compile
   char[][] words = [ "hello", "world" ];

Yes it does:

Huh. Am I confusing that with some other (similar) issue? Of course, if I'm totally out in left-field, then I'm happy to see the resolution of something that was an issue in the past (wasn't it?).

It was, at least for the (very short) time after array literals were released. They were fixed in the very next patch, if I remember correctly.
Mar 27 2008
prev sibling next sibling parent reply e-t172 <e-t172 akegroup.org> writes:
Benji Smith a écrit :
 I also would have preferred to have growable arrays and associative 
 arrays in the standard library than in the language.
 
   // Would be ideal. Growable arrays would be best implemented as a
   // templatized collection class.
   List!(String) words = [ "hello, "world" ];

Did you read http://www.digitalmars.com/d/2.0/builtin.html ?
Mar 27 2008
parent reply Benji Smith <benji benjismith.net> writes:
e-t172 wrote:
 Benji Smith a écrit :
 I also would have preferred to have growable arrays and associative 
 arrays in the standard library than in the language.

   // Would be ideal. Growable arrays would be best implemented as a
   // templatized collection class.
   List!(String) words = [ "hello, "world" ];

Did you read http://www.digitalmars.com/d/2.0/builtin.html ?

Yeah, and while there are some good points to consider there, think about this... The d language includes 3 different kinds of containers: * Fixed-size immutable lists of immutable values (aka, static arrays) * Growable im/mutable lists, of im/mutable values (aka, dynamic arrays) * Growable im/mutable maps, with hashed buckets, backed by red-black-trees (aka. associative arrays). What about all the other types of containers? * Sets/MutliSets/SortedSets (backed by hashtables or trees) * SortedMaps/MultiMaps (backed by hashtables or trees) * LinkedLists/SkipLists * BinaryTrees/N-AryTrees/BTrees * Heaps Why the special syntax and compiler support for only a small portion of the container family? Really, shouldn't there also be a built in 'set' implementation as well? And, while it's straightforward to develop multiple implementations of a standard container interface (like Map or List) with different data structures, it's impossible to replace the data structures backing an associative array or a dynamic array. When an API developer writes a method expecting a map container (with keys and values), the developer is forced to choose between a polymorphic library implementation and a non-polymorphic associative array implementation): doSomething(Map!(K, V) map); doSomething(K[V] map); The interface-based library implementation allows the function to accept multiple types of data structures, as long as they support the map interface. Users of the built-in assoc array function are stuck with the compiled-in implementation of the type. And the built-in implementations don't play nicely with a full container library. Right now, the associative array type is defined as an *UNORDERED* collection, allowing no duplicate keys (but potential duplication of values). If you call its .keys property, you get back a dynamic array of its keys, but a dynamic array is an *ORDERED* collection that permits duplicates, so the returned collection distorts the contract of the collection that produced it. A container library might implement a new Set interface, as an unordered collection of non-duplicate values. The consumers of the Map interface would probably like the Map.keys property to return a Set, since it paints a clearer picture of the Map contract. But users of associative arrays won't be able to do the same. They'll be stuck with the built-in behavior. Anyhow, those are just a few thoughts. The built-in collection of types should include types with only one sensible implementation. A fixed-size list has only one sensible implementation: an array. So it makes sense for it to built in. That's why I think the other types would be more at home in a library. --benji
Mar 27 2008
next sibling parent reply Michiel Helvensteijn <nomail please.com> writes:
Benji Smith wrote:

 The built-in collection of types should include types with only one
 sensible implementation. A fixed-size list has only one sensible
 implementation: an array. So it makes sense for it to built in.
 
 That's why I think the other types would be more at home in a library.

Now that you mention it, I've been thinking about that as well. I know what you mean. However, we also want the syntactic sugar for maps and dynamic arrays. int[] is just so much prettier than vector!(int). So why not allow a library to define what an int[] or int[T] means? This would only work, however, if: * No clashing implementations can be imported at the same time. (Just like two classes with the same name can't coexist.) * There is a default implementation for which you need no imports. -- Michiel
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michiel Helvensteijn wrote:
 So why not allow a library to define what an int[] or int[T] means? This
 would only work, however, if:
 
 * No clashing implementations can be imported at the same time. (Just like
 two classes with the same name can't coexist.)
 * There is a default implementation for which you need no imports.

Like you suggested, the problem with a library defining how it works is that the library would have to be standardized so that code could interoperate, and this negates all the advantages of having it be in a library.
Mar 27 2008
parent Michiel Helvensteijn <nomail please.com> writes:
Walter Bright wrote:

 So why not allow a library to define what an int[] or int[T] means? This
 would only work, however, if:
 
 * No clashing implementations can be imported at the same time. (Just
 like two classes with the same name can't coexist.)
 * There is a default implementation for which you need no imports.

Like you suggested, the problem with a library defining how it works is that the library would have to be standardized so that code could interoperate, and this negates all the advantages of having it be in a library.

That's going to be a problem anyway, when people start using library vectors and maps because of the limitations of standard D containers (the .keys example was a good one, I think). Especially since D has two widely used, competing libraries. But it can be solved, surely? Just make sure you have functions in the working referencing environment that can convert from one type to the other automatically when needed. Sure, this might result in slower code than forcing people to use the same type everywhere, but that's just unrealistic. -- Michiel
Mar 27 2008
prev sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
Benji Smith wrote:
 e-t172 wrote:
 Benji Smith a écrit :
 I also would have preferred to have growable arrays and associative 
 arrays in the standard library than in the language.

   // Would be ideal. Growable arrays would be best implemented as a
   // templatized collection class.
   List!(String) words = [ "hello, "world" ];

Did you read http://www.digitalmars.com/d/2.0/builtin.html ?

Yeah, and while there are some good points to consider there, think about this... The d language includes 3 different kinds of containers: * Fixed-size immutable lists of immutable values (aka, static arrays) * Growable im/mutable lists, of im/mutable values (aka, dynamic arrays) * Growable im/mutable maps, with hashed buckets, backed by red-black-trees (aka. associative arrays). What about all the other types of containers?

Exactly the same thought here.
Mar 27 2008
prev sibling next sibling parent reply Michiel Helvensteijn <nomail please.com> writes:
Benji Smith wrote:

 CONST

I think most people will agree with you here.
 STRINGS
 
 ...
 
 I would have liked to see just one string type, with encoding kept as an
 internal implementation detail. And I'd much rather have a string class
 than to treat strings as character arrays

In fact, I thought that using char[] instead of a class as the string type (with a type alias 'string', of course), was a great idea in the case of D. In C++ it doesn't work so well, because arrays there are just pointers, don't know their own size, and cannot grow dynamically. So a class was the natural solution. But D arrays can do all those things, and they even have nice syntactic advantages like slicing, concatenating and function-dot-notation. So I don't see a reason to use a class here.
 (especially since indexing/slicing deals with code-points rather than
 character positions). 

I'm not quite sure what you mean by this. What are code-points?
 KEYWORD OVERLOAD

Agreed.
 ARRAYS

Agreed, mostly. Though D arrays are a whole lot prettier than C++ arrays.
 ANYHOW...
 
 ...
 
 I feel like, if I'm going to use such a complex language, I may as well
 choose C++, which offers the advantages of ubiquity and language
 stability.

This is the exact reason I'm still choosing C++ over D. I suppose you could restrict yourself to D 1.0. I'm told the newest D is a development version only. However, I don't feel easy using it for big projects knowing the direction D is taking. -- Michiel
Mar 27 2008
next sibling parent reply "Saaa" <empty needmail.com> writes:
Why feel uneasy when D1.0 is stable, your project will always compile with 
DMD 1.x

 I suppose you could restrict yourself to D 1.0. I'm told the newest D is a
 development version only. However, I don't feel easy using it for big
 projects knowing the direction D is taking.

 -- 
 Michiel
 

Mar 27 2008
parent reply Michiel Helvensteijn <nomail please.com> writes:
Saaa wrote:

 I suppose you could restrict yourself to D 1.0. I'm told the newest D is
 a development version only. However, I don't feel easy using it for big
 projects knowing the direction D is taking.

Why feel uneasy when D1.0 is stable, your project will always compile with DMD 1.x

It's just knowing that I can't stay on the bleeding edge. There are in fact some features of D 2.0 I would like to use, but can't, because it's all or nothing. -- Michiel
Mar 27 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Michiel Helvensteijn wrote:
 Saaa wrote:
 
 I suppose you could restrict yourself to D 1.0. I'm told the newest D is
 a development version only. However, I don't feel easy using it for big
 projects knowing the direction D is taking.

DMD 1.x

It's just knowing that I can't stay on the bleeding edge. There are in fact some features of D 2.0 I would like to use, but can't, because it's all or nothing.

It's just not possible to have a stable language yet have it be on the bleeding edge.
Mar 27 2008
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Michiel Helvensteijn:
 I'm not quite sure what you mean by this. What are code-points?

The simpler intro to such topic, "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)", by Joel Spolsk: http://www.joelonsoftware.com/articles/Unicode.html Bye, bearophile
Mar 27 2008
parent Michiel Helvensteijn <nomail please.com> writes:
bearophile wrote:

 I'm not quite sure what you mean by this. What are code-points?

The simpler intro to such topic, "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)", by Joel Spolsk: http://www.joelonsoftware.com/articles/Unicode.html

Ah. Thanks! I'd been (passively) looking for something like that. Turns out, I know most of this. But I didn't know the term code-points. :-) -- Michiel
Mar 27 2008
prev sibling parent reply Benji Smith <benji benjismith.net> writes:
Michiel Helvensteijn wrote:
 I suppose you could restrict yourself to D 1.0. I'm told the newest D is a
 development version only. However, I don't feel easy using it for big
 projects knowing the direction D is taking.

Since I try to keep up with the NG, I can't even really remember what D 1.0 consists of anymore (except that it lacks const), and I couldn't find any documentation anywhere about differences between the language semantics of the two versions (short of diffing the HTML docs). Is there anything online that gives bullet-points about the differences? --benji
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Benji Smith wrote:
 Since I try to keep up with the NG, I can't even really remember what D 
 1.0 consists of anymore (except that it lacks const), and I couldn't 
 find any documentation anywhere about differences between the language 
 semantics of the two versions (short of diffing the HTML docs).
 
 Is there anything online that gives bullet-points about the differences?

http://www.digitalmars.com/d/2.0/features2.html
Mar 27 2008
next sibling parent reply Benji Smith <benji benjismith.net> writes:
Walter Bright wrote:
 Benji Smith wrote:
 Is there anything online that gives bullet-points about the differences?

http://www.digitalmars.com/d/2.0/features2.html

Aha! Thanks! How did I miss that??? --benji
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Benji Smith wrote:
 How did I miss that???

It's not hard to miss, the link to it is a bit buried.
Mar 27 2008
parent Georg Wrede <georg nospam.org> writes:
Walter Bright wrote:
 Benji Smith wrote:
 
 How did I miss that???

It's not hard to miss, the link to it is a bit buried.

Duh? Argh!
Mar 27 2008
prev sibling parent reply Benji Smith <benji benjismith.net> writes:
Walter Bright wrote:
 Benji Smith wrote:
 Since I try to keep up with the NG, I can't even really remember what 
 D 1.0 consists of anymore (except that it lacks const), and I couldn't 
 find any documentation anywhere about differences between the language 
 semantics of the two versions (short of diffing the HTML docs).

 Is there anything online that gives bullet-points about the differences?

http://www.digitalmars.com/d/2.0/features2.html

Hmmmm... I'll have to think about using the 1.0 version. (Though I'm not crazy about adopting a language that seems to be moving in a direction that significantly differs with my own philosophy). Can Tango be used with the 1.0 compiler? --benji
Mar 27 2008
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Benji Smith wrote:
 Can Tango be used with the 1.0 compiler?

Heh. AFAIK it can *only* be used with a 1.0 compiler. (Though a D2 port is/was in the works)
Mar 27 2008
prev sibling next sibling parent "Vladimir Panteleev" <thecybershadow gmail.com> writes:
On Thu, 27 Mar 2008 19:26:35 +0200, Benji Smith <benji benjismith.net> w=
rote:

 STRINGS

 The existence of three different string types (six, if you count
 const/mutable variations of each) makes text-processing more difficult=

 than it ought to be.

I don't think this is suitable for a high-performance, Unicode-ready, sy= stem programming language. UTF-8 is used most commonly as it's the most = space-efficient; UTF-16 is good for OSes which use it or wide strings (e= .g. Windows NT); UTF-32 is used where quick indexing is required. Having= a "black box" string type which does all these conversions "on-demand" = does not fit in with D, IMO.
 And I'd much rather have a string class
 than to treat strings as character arrays (especially since
 indexing/slicing deals with code-points rather than character position=

Something like this would either be performance or memory-inefficient in= most cases - it can be done by: 1) storing the string using the smallest character type that can fit any= of the characters in the string (example implementation: http://www.dpr= ogramming.com/dstring.php ) - this can cause reencoding as you add data = on the string, and a large text with just a few Unicode characters can t= ake up almost 4 times as much as the UTF-8 version 2) scanning the entire string on each index - slow indexing 3) keep some lookup tables to speed up 2) - not as slow but requires add= itional memory Doesn't look like a panacea to me :)
 KEYWORD OVERLOAD

 The mandate to keep keyword count as low as possible has been a real
 detriment to the language.

 Each unique concept should have its own unique keyword.

D is quite a feature-rich language... I'd imagine it would get quite dif= ficult to find simple, memorizable and unique keywords for every new fea= ture without introducing new syntax (using non-word characters).
 what I really want is a non-growable array whose size isn't known unti=

What advantages does a reference-type non-growable dynamic array have? O= r you mean a value-type array, which will get copied on every assignment= ?
   // Inplicit conversion. Does this copy data?

Dynamic arrays are reference types, slices of memory; no data is implici= tly copied. =
    // Error: functions can't return fixed-length arrays!

I agree that this is silly and should be fixed; wrapping the static arra= y in a struct works anyway.
    // Doesn't compile
    char[][] words =3D [ "hello", "world" ];

You probably mean the issue when the strings are of different length: char[][] words =3D [ "hello", "world!" ]; Agreed - the compiler should detect that and choose the type not just ba= sed on the first element.
 2) An empty array is equal to a null pointer. Yikes!

Could you bring a practical example of where this is a problem? -- = Best regards, Vladimir mailto:thecybershadow gmail.com
Mar 27 2008
prev sibling next sibling parent =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
On Thu, 27 Mar 2008, Benji Smith wrote:

 Nevertheless, the things that keep me interested in D are:

 * Multi-platform, compiled to machine code. No VM required.

 * No header files.

 * No preprocessor.

 * Built-in garbage collection.

 * Real structs

 * Semantic import, rather than lexical #include.

 * No need for forward declarations.

FWIW, these are pretty standard features in any modern language. If you don't need maximum speed, good compatibility with C++ nor extensive metaprogramming facilities, there are huge amount of alternatives. Some languages even take orthogonality and stability very seriously and avoid featuritism like the plague.
 * Single inheritance, and interfaces.

I think Scala style OOP systems are becoming more common these days.
Mar 27 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
I appreciate the time and effort you made to explain your thoughts. I'll 
try and answer them.

Benji Smith wrote:
 CONST
 
 Const is a total trainwreck, and is the biggest reason for me to stay 
 away from D in a real project. Even now, nearly a year after the 
 introduction of const/final/invariant, there are still NG threads with 
 more than a hundred posts with people trying to understand how const is 
 supposed to work and how they can accomplish (really simple) goals under 
 the current const regime.
 
 Before the advent of the various const implementations, I could glance 
 at a function declaration and know exactly what it meant. Now it takes 
 much more effort to understand even the most const-aware functions and 
 develop a strategy for working with them in an application.
 
 Even if I liked the current semantics, everything still seems so 
 up-in-the-air with const, I'd be loathe to dive in until it stabilized. 
 And I don't see that happening anytime soon.
 
 It seems like most of the people weighing in on the const debate are 
 trying to figure out a type system and a set of operations that will 
 support all possible use cases. (Like the recent "const debacle" thread.)
 
 It seems like const will either become too complex for ordinary usage 
 (and will be worked-around more often than used properly) or it will 
 become too weak to be enforce absolute safety/optimization guarantees.
 
 Personally, I'd rather have no concept of const at all than adopt any of 
 the implementations that have been proposed so far.

I understand your and others' frustration with const, and here's what I think it is based on: 1) We worked hard on what is the right way to do const for a year. This included at least 3 very different implementations of const that were released. The first two turned out to be very wrong and unworkable, and we learned from that how to do it right. The problem is, we burned up a lot of goodwill with it. Many people simply tuned out with "const is bad". Many of the rest bring baggage from the previous const regimes along that impair understanding of the current const regime. 2) The current const regime came with a number of bugs in the implementation of it that further messed up peoples' understanding of what it was all about and how it was supposed to work. Most of these have been fixed, but they've still left a bad taste and even more people have tuned out with "const is bad". 3) The const regime is completely based on the idea of transitivity of const. The problem is, D is the *only* language with a notion of transitivity in it. A few academics know about it, but hardly any practicing programmers. There is essentially no popular literature about it. Mention transitivity to an experienced C++ or Java programmer, and you'll get a completely blank look. In other words, not only do we need to explain how transitivity works in particular in D, we have to explain what transitivity does and what it is good for. For such a foreign concept, this is a tall order. I'm not so good at being a teacher, I tend to explain how things work in D by saying "it works just like X in language Y except with this little tweak." I can't do that with transitive const. Andrei and I have spent many, many hours sitting at a table with smart people explaining what transitivity is. It is not an easy concept. Hey, I didn't get it for a long time, either, which is partly why the first two const regimes in D were wrong. 4) The C++ const is ubiquitous and a lot of people are comfortable with it, but it turns out that few understand what it guarantees and what it doesn't. C++'s const is so weak that it is more of a convention than a guarantee. This weakness enables things to be done with it that are just fundamentally unsound, and contribute to C++ being a very difficult language to write and verify sound code in. So, with all these things working against D const, there ought to be some compelling reasons for us to swim against the tide and say it's worth it: 1. It makes function interfaces more self-documenting. Without transitive const, for all pointer/reference parameters one must rely on the documentation (which is always missing, out of date, or wrong). Note that without transitivity, C++ const is nearly useless for such self-documentation, which is why C++ programmers tend to rely on convention instead. 2. It makes for interfaces that can be relied upon, which becomes increasingly important the more people that are involved with the code. In other words, it scales very well. People who are involved with projects with large teams of programmers tell me that lack of const makes their lives difficult because they cannot rely on the compiler to enforce convention. The larger the team, the worse it gets. Managing APIs is critical to a large project - it's why BASIC doesn't scale (for an extreme example). 3. Const transitivity makes for some interesting optimization opportunities. The value of this has not been explored or exploited. 4. Here's the biggie. Points 1..3 are insignificant in comparison. The future of programming will be multicore, multithreaded. Languages that make it easy to program them will supplant languages that don't. Transitive const is key to bringing D into this paradigm. The surge in use of Haskell and Erlang is evidence of this coming trend (the killer feature of those languages is they make it easy to do multiprogramming). C++ cannot be retrofitted to supporting multiprogramming in a manner that makes it accessible. D isn't there yet, but it will be, and transitive const will be absolutely fundamental to making it work. Of course, if you're writing single-threaded one man programs of fairly modest size, const is not particularly useful. I quite agree with that. And in D you can effectively ignore const by just not using it, or by using D 1.0. The only place const is imposed is with the immutable string type.
Mar 27 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 3) The const regime is completely based on the idea of transitivity of
 const. The problem is, D is the *only* language with a notion of
 transitivity in it. A few academics know about it, but hardly any
 practicing programmers. There is essentially no popular literature about
 it. Mention transitivity to an experienced C++ or Java programmer, and
 you'll get a completely blank look.

Really? Transitivity is covered in basic math and logic courses. I'd think they would grasp the idea immediately. My only remaining issue with const is simply the choice of keywords for each meaning, and specifically, that the meaning of "const" not only changed from 1.0 to 2.0, but actually weakened. Sean
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 3) The const regime is completely based on the idea of transitivity of
 const. The problem is, D is the *only* language with a notion of
 transitivity in it. A few academics know about it, but hardly any
 practicing programmers. There is essentially no popular literature about
 it. Mention transitivity to an experienced C++ or Java programmer, and
 you'll get a completely blank look.

Really? Transitivity is covered in basic math and logic courses. I'd think they would grasp the idea immediately.

They don't. I speak from personal experience. Even for the ones who do understand transitivity, understanding the implications of it for const takes a lot longer.
 My only remaining issue with
 const is simply the choice of keywords for each meaning, and specifically,
 that the meaning of "const" not only changed from 1.0 to 2.0, but actually
 weakened.

Every time we tried to address that, we wound up with a system that didn't work.
Mar 27 2008
next sibling parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
Walter Bright wrote:

 Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 3) The const regime is completely based on the idea of transitivity of
 const. The problem is, D is the *only* language with a notion of
 transitivity in it. A few academics know about it, but hardly any
 practicing programmers. There is essentially no popular literature about
 it. Mention transitivity to an experienced C++ or Java programmer, and
 you'll get a completely blank look.

Really? Transitivity is covered in basic math and logic courses. I'd think they would grasp the idea immediately.

They don't. I speak from personal experience. Even for the ones who do understand transitivity, understanding the implications of it for const takes a lot longer.
 My only remaining issue with
 const is simply the choice of keywords for each meaning, and
 specifically, that the meaning of "const" not only changed from 1.0 to
 2.0, but actually weakened.

Every time we tried to address that, we wound up with a system that didn't work.

You haven't tried it in a public release despite massive backing (in the NG at least). -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Mar 27 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Lars Ivar Igesund wrote:
 You haven't tried it in a public release despite massive backing (in the NG
 at least).

Jerking people around with yet another non-working const regime would not help. For example, the C++ const regime has massive backing from the C++ community. But it is fundamentally unsound. If you carefully monitor the email traffic of people working on C++0x, you'll see the problems, too. As programming shifts to more and more multiprogramming, and people get more and more fed up with programs that defy static verification, these unfixable problems will cause more and more people to abandon C++. D needs to look to the future, and for that it needs a fundamentally (i.e. mathematically) sound foundation for const.
Mar 27 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 My only remaining issue with
 const is simply the choice of keywords for each meaning, and specifically,
 that the meaning of "const" not only changed from 1.0 to 2.0, but actually
 weakened.

didn't work.

I'm not sure I understand. What I meant was that I didn't agree with the choice of keywords for const behavior in D 2.0--I have no major issue with the functionality itself. In particular, I don't like that "const" in D 1.0 means "will never change" but in D 2.0 "const" means "read-only view" while an entirely new keyword was chosen for "will never change." Thus the meaning of "const" is different from D 1.0 to D 2.0, and not only is it different, but the meaning is weaker. This means that 1.0 code will compile just fine in 2.0 but can't rely on the same guarantees as 1.0 code can, which complicates maintenance if the code is intended to be cross-compatible. I'm sure this won't bother me so much once D 1.0 is a distant memory, but in the interim it's somewhat painful. That's all :-) Sean
Mar 27 2008
next sibling parent reply Georg Wrede <georg nospam.org> writes:
Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 
Sean Kelly wrote:

My only remaining issue with
const is simply the choice of keywords for each meaning, and specifically,
that the meaning of "const" not only changed from 1.0 to 2.0, but actually
weakened.

Every time we tried to address that, we wound up with a system that didn't work.

I'm not sure I understand. What I meant was that I didn't agree with the choice of keywords for const behavior in D 2.0--I have no major issue with the functionality itself. In particular, I don't like that "const" in D 1.0 means "will never change" but in D 2.0 "const" means "read-only view" while an entirely new keyword was chosen for "will never change." Thus the meaning of "const" is different from D 1.0 to D 2.0, and not only is it different, but the meaning is weaker. This means that 1.0 code will compile just fine in 2.0 but can't rely on the same guarantees as 1.0 code can, which complicates maintenance if the code is intended to be cross-compatible. I'm sure this won't bother me so much once D 1.0 is a distant memory, but in the interim it's somewhat painful. That's all :-)

It's also an undue burden for any programmer who codes in both 1&2. And that tends (in my humble experience) cause a lot of bugs, which at least the programmer himself has a very hard time noticing. And few of us have another D1-only or D2-only colleague who'd spot them. ( There ought to be a web site with anti-patterns for language development: semantics, syntax, homonyms, almost-alike-when-not and unlike-when-actually-same structures, elements, and names. And obfuscation of true meaning, origin and structure through cavalier sprinkling of syntactic sugar. ) More seriously, having to teach the particular language (be it high-school or university), gives one plenty more insight into this than I can even begin to say.
Mar 27 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Georg Wrede (georg nospam.org)'s article
 More seriously, having to teach the particular language (be it
 high-school or university), gives one plenty more insight into this than
 I can even begin to say.

This is why I've never understood the argument that a language must have as few keywords as it can get away with. In my experience, having the same symbol represent multiple concepts tends to cause confusion. The ideal situation is to have a simple syntax so only a few keywords are necessary, but barring that, I'd think that choosing an expressive and appropriate symbology for each situation would be best. To me, it seems that the "minimize keyword count" idea began as a way to verify conceptual simplicity and has since become an arbitrary metric that measures nothing. Sean
Mar 27 2008
next sibling parent Georg Wrede <georg nospam.org> writes:
Sean Kelly wrote:
 == Quote from Georg Wrede (georg nospam.org)'s article
 
 More seriously, having to teach the particular language (be it 
 high-school or university), gives one plenty more insight into this
 than I can even begin to say.

To me, it seems that the "minimize keyword count" idea began as a way to verify conceptual simplicity and has since become an arbitrary metric that measures nothing.

Yes. Somebody trying to convince me otherwise would have a hell of a job!
Mar 27 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Sean Kelly wrote:
 This is why I've never understood the argument that a language must have
 as few keywords as it can get away with.  In my experience, having the
 same
 symbol represent multiple concepts tends to cause confusion.  The ideal
 situation is to have a simple syntax so only a few keywords are necessary,
 but barring that, I'd think that choosing an expressive and appropriate
 symbology for each situation would be best.  To me, it seems that the
 "minimize keyword count" idea began as a way to verify conceptual
 simplicity and has since become an arbitrary metric that measures
 nothing.

I couldn't agree more! keyword minimization is another horrible idea inherited from the C++ world where backwards compatibility is a major concern. (Ok, I'm guessing at that, but it's the only semi-sane argument I can come up with) IMHO, new keywords should be used for distinct functionality... I don't care if Andrei like it instantly or not! My only problem with the current const design is the use of keywords. The manifest constant thing created a whole new storm about wording choice. Eventually, people settled on manifest as the best keyword. If nothing else, it forced a coder to go look it up to find what it means! Back when everyone was trying to understand the new const designs, we all called const "readonly". Every time someone asks today, we always describe it as readonly. Why not use that term if it makes sense to everyone?!
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 Back when everyone was trying to understand the new const designs, we all
 called const "readonly".  Every time someone asks today, we always describe
 it as readonly. Why not use that term if it makes sense to everyone?!

const, readonly, invariant, and immutable all mean exactly the same thing.
Mar 27 2008
next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Fri, 28 Mar 2008 04:06:21 +0100, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Jason House wrote:
 Back when everyone was trying to understand the new const designs, we  
 all
 called const "readonly".  Every time someone asks today, we always  
 describe
 it as readonly. Why not use that term if it makes sense to everyone?!

const, readonly, invariant, and immutable all mean exactly the same thing.

As words, yes. But in D, const is "readonly", invariant is "will never change". And enum is...
Mar 27 2008
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
Walter Bright wrote:
 Jason House wrote:
 Back when everyone was trying to understand the new const designs, we all
 called const "readonly".  Every time someone asks today, we always 
 describe
 it as readonly. Why not use that term if it makes sense to everyone?!

const, readonly, invariant, and immutable all mean exactly the same thing.

...and yet we currently use 'const' and 'invariant' for two entirely different concepts.
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 Jason House wrote:
 Back when everyone was trying to understand the new const designs, we 
 all
 called const "readonly".  Every time someone asks today, we always 
 describe
 it as readonly. Why not use that term if it makes sense to everyone?!

const, readonly, invariant, and immutable all mean exactly the same thing.

...and yet we currently use 'const' and 'invariant' for two entirely different concepts.

Yes. I suppose we could invent a name, like frzapper instead, but I don't think that would help.
Mar 28 2008
next sibling parent reply Roberto Mariottini <rmariottini mail.com> writes:
Walter Bright wrote:
[...]
 Yes. I suppose we could invent a name, like frzapper instead, but I 
 don't think that would help.

I think it may help. In my experience adding new keywords is often less painful than it seems. For example Java added the (probably unneeded) keywords 'extends' and 'implements' without creating a single problem. No programmer coming from C or C++ have had any problems with 'extends' and 'implements'. On the other side, changing the meaning of a well known keyword can be very painful: it's still difficult to figure out that 'long' in Java means a 64 bit integer. Ciao P.S.: I'm not a native English speaker, and I've learned programming without knowing a word of English. I can assure you that even if 'while', 'for', 'read', 'float', 'thread' were unknown words for me, I've learned their meaning anyways. Imagine also a Japanese or Chinese programmer: for her even 'integer' means nothing (so I was lucky!). Still there are millions of Japanese and Chinese programmers. And 'long', 'short', 'double', 'float', have lost their original English meaning long ago. -- Roberto Mariottini, http://www.mariottini.net/roberto/ SuperbCalc, a free tape calculator: http://www.mariottini.net/roberto/superbcalc/
Mar 28 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Roberto Mariottini wrote:
 Walter Bright wrote:
 [...]
 Yes. I suppose we could invent a name, like frzapper instead, but I 
 don't think that would help.

I think it may help. In my experience adding new keywords is often less painful than it seems. For example Java added the (probably unneeded) keywords 'extends' and 'implements' without creating a single problem. No programmer coming from C or C++ have had any problems with 'extends' and 'implements'.

Well, I did, simply because 'extends' was annoying to type, where C++ simply used ':'.
 On the other side, changing the meaning of a well known keyword can be 
 very painful: it's still difficult to figure out that 'long' in Java 
 means a 64 bit integer.

It's a little silly to have 'int' and 'long' both mean 32 bits.
 P.S.: I'm not a native English speaker, and I've learned programming 
 without knowing a word of English.
 I can assure you that even if 'while', 'for', 'read', 'float', 'thread' 
 were unknown words for me, I've learned their meaning anyways.
 Imagine also a Japanese or Chinese programmer: for her even 'integer' 
 means nothing (so I was lucky!). Still there are millions of Japanese 
 and Chinese programmers.
 And 'long', 'short', 'double', 'float', have lost their original English 
 meaning long ago.

Sure. At some level it's pointless to keep the original English meanings because the whole reason we have programming languages instead of English is because English is ambiguous and imprecise. Every computer language has to invent its own meanings.
Mar 28 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Walter Bright wrote:
 Jason House wrote:
 Back when everyone was trying to understand the new const designs, we
 all
 called const "readonly".  Every time someone asks today, we always
 describe
 it as readonly. Why not use that term if it makes sense to everyone?!

const, readonly, invariant, and immutable all mean exactly the same thing.

...and yet we currently use 'const' and 'invariant' for two entirely different concepts.

don't think that would help.

Surely you aren't suggesting that the English language consists entirely of four words, all which have the same meaning? That aside, my point was that I find it somewhat troubling that you feel this way and yet still chose the keywords that we have now. Surely, a language should prefer a literal representation which accurately describes the underlying concept being symbolized. If you actually felt that 'const' and 'invariant' had distinct meanings which were appropriate for the underlying concepts then I'd feel more at ease, even if I didn't agree. Sean
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 Surely you aren't suggesting that the English language consists entirely of
 four words, all which have the same meaning?  That aside, my point was
 that I find it somewhat troubling that you feel this way and yet still chose
 the keywords that we have now.  Surely, a language should prefer a literal
 representation which accurately describes the underlying concept being
 symbolized.  If you actually felt that 'const' and 'invariant' had distinct
 meanings which were appropriate for the underlying concepts then I'd
 feel more at ease, even if I didn't agree.

But there aren't any such words - what word means "read only view, but others can modify the value" ? "readonly" isn't it, as that commonly means in embedded systems "nobody can write it" and has been used as a storage class to mean just that in embedded systems languages.
Mar 28 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Surely you aren't suggesting that the English language consists entirely of
 four words, all which have the same meaning?  That aside, my point was
 that I find it somewhat troubling that you feel this way and yet still chose
 the keywords that we have now.  Surely, a language should prefer a literal
 representation which accurately describes the underlying concept being
 symbolized.  If you actually felt that 'const' and 'invariant' had distinct
 meanings which were appropriate for the underlying concepts then I'd
 feel more at ease, even if I didn't agree.

others can modify the value" ? "readonly" isn't it, as that commonly means in embedded systems "nobody can write it" and has been used as a storage class to mean just that in embedded systems languages.

I've suggested "view" in the past, and there must be others. Alternately, invent a word as you've said or come up with syntax that doesn't require a keyword to indicate this concept. Truth be told however, my issue with the keywords in 2.0 has more to do with the change in meaning of "const" than with the words themselves. My initial response above was simply an expression of surprise that you felt the words all had identical meanings and yet we were using them to represent different things. Sean
Mar 28 2008
next sibling parent reply renoX <renosky free.fr> writes:
Sean Kelly a écrit :
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Surely you aren't suggesting that the English language consists entirely of
 four words, all which have the same meaning?  That aside, my point was
 that I find it somewhat troubling that you feel this way and yet still chose
 the keywords that we have now.  Surely, a language should prefer a literal
 representation which accurately describes the underlying concept being
 symbolized.  If you actually felt that 'const' and 'invariant' had distinct
 meanings which were appropriate for the underlying concepts then I'd
 feel more at ease, even if I didn't agree.

others can modify the value" ? "readonly" isn't it, as that commonly means in embedded systems "nobody can write it" and has been used as a storage class to mean just that in embedded systems languages.

I've suggested "view" in the past,

I like it a lot: view as in 'view but don't touch' :-) renoX
and there must be others.  Alternately,
 invent a word as you've said or come up with syntax that doesn't require
 a keyword to indicate this concept.  Truth be told however, my issue with
 the keywords in 2.0 has more to do with the change in meaning of "const"
 than with the words themselves.  My initial response above was simply an
 expression of surprise that you felt the words all had identical meanings
 and yet we were using them to represent different things.
 
 
 Sean

Mar 28 2008
next sibling parent renoX <renosky free.fr> writes:
Janice Caron a écrit :
 On 28/03/2008, renoX <renosky free.fr> wrote:
  > I've suggested "view" in the past,

 I like it a lot: view as in 'view but don't touch' :-)

I like that one too. It's shorter than "readonly" as well, which is another big plus.

Yes, I just realised that in the sentence 'read only view' in fact the most important part is the 'view', and read only is not fully true so it's a view: if everyone's only looking at something, of course this thing won't change but if someone modifies it, everyone will see the change.
 Under that regime, my "ideal" would be
 
     in -> view
     const -> view
     invariant -> const

Agreed.
     enum -> const

I'd say that here both enum and const could be interesting: -const for 'traditional enum' and -enum for 'named' enumerated objects which you could print the name.. It has always shocked me that with C/C++ (and currently D)'s enum you refer inside the program to an enum by it's label but outside you can't unless the developer makes the effort of maintaining a map (value -> 'value string'), or then you have some documentation which must be maintained too :-( But this would have the downside of surprising C, D1 developers so 'named enum' -> label or something similar. Regards, renoX
Mar 28 2008
prev sibling parent reply Denton Cockburn <diboss hotmail.com> writes:
On Fri, 28 Mar 2008 19:58:37 +0000, Janice Caron wrote:

 Under that regime, my "ideal" would be
 
     in -> view
     const -> view
     invariant -> const
     enum -> const

+1 I too dislike the fact that const has a completely different meaning in D1 and D2. It's strange to see the meanings of keywords change.
Mar 29 2008
parent "Hans W. Uhlig" <huhlig clickconsulting.com> writes:
Scott S. McCoy wrote:
 
 I don't think types should consist of compound phrases.  /viewof/ sounds 
 like a method name, not a part of the primitive type system.  If you 
 forget about the existing /const/ in D 1, /const/ beats out /viewof/ on 
 several counts:
 

An alternative is you could call it "sacred" or "shielded", while it may sound silly having a sacred array[] would be a rather distinct way of saying lookie but no touchie.
Mar 30 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 I've suggested "view" in the past, and there must be others.

"view" doesn't imply that one cannot change it through that view.
 Alternately,
 invent a word as you've said or come up with syntax that doesn't require
 a keyword to indicate this concept.  Truth be told however, my issue with
 the keywords in 2.0 has more to do with the change in meaning of "const"
 than with the words themselves.

const in D pretty much has the same meaning as C++ const as far as being a readonly view. The C++ meaning has a lot of momentum behind it.
 My initial response above was simply an
 expression of surprise that you felt the words all had identical meanings
 and yet we were using them to represent different things.

I meant they have identical english meanings.
Mar 28 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 I've suggested "view" in the past, and there must be others.


It certainly does to me. But this is obviously a matter of opinion.
 Alternately,
 invent a word as you've said or come up with syntax that doesn't require
 a keyword to indicate this concept.  Truth be told however, my issue with
 the keywords in 2.0 has more to do with the change in meaning of "const"
 than with the words themselves.

a readonly view. The C++ meaning has a lot of momentum behind it.

So why use 'const' to mean ROM-able in D 1.0? Within the context of D, 'const' already has an established meaning, and I'd consider that more important. Please note that the reason I originally brought up const stuff at all was because I dislike that the meaning of 'const' changed between 1.0 and 2.0, and in such a way that the 2.0 compiler will silently accept code written for 1.0 but that the meaning will be different. I really didn't intend for the conversation to end up being about the meaning of words. Frankly, I'd long since given up the const issue as lost anyway--I really have no idea why I decided to say anything now at all. Sean
Mar 28 2008
prev sibling parent Regan Heath <regan netmail.co.nz> writes:
Walter Bright wrote:
 Sean Kelly wrote:
 I've suggested "view" in the past, and there must be others.

"view" doesn't imply that one cannot change it through that view.

"viewonly" then :) Regan
Mar 31 2008
prev sibling next sibling parent Jason House <jason.james.house gmail.com> writes:
Walter Bright wrote:

 Jason House wrote:
 Back when everyone was trying to understand the new const designs, we all
 called const "readonly".  Every time someone asks today, we always
 describe it as readonly. Why not use that term if it makes sense to
 everyone?!

const, readonly, invariant, and immutable all mean exactly the same thing.

That really is not the point. As a community, after much debate, the community as a whole settled on readonly as the best of all evils... and settled on manifest as the best of all alternatives... To mass surprise, alternate keywords were chosen. It just continues to give the impression that the community as a whole can debate all they want, but regardless of what we say or do, it's a one man show. It's true that a CEO has all the power, but the most successful companies have CEO that listen to all the people around him. Any good will that was lost with me revolves around the nature of communication. At some point in the near future, I'll expand upon that as a new thread (maybe after this current thing dies down)
Mar 28 2008
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2008-03-27 23:06:21 -0400, Walter Bright <newshound1 digitalmars.com> said:

 Jason House wrote:
 Back when everyone was trying to understand the new const designs, we all
 called const "readonly".  Every time someone asks today, we always describe
 it as readonly. Why not use that term if it makes sense to everyone?!

const, readonly, invariant, and immutable all mean exactly the same thing.

But const in D 1.0 and D 2.0 doesn't mean the same thing does it? I think using readonly for what is const in D 2.0 and const for what is invariant makes more sense... although just like you I don't like much the name "readonly" for that meaning: it looks too much like a synonym. Ever thought of "shut", "guarded", "shielded", "occluded", or anything else conceptualizing some kind of barrier instead of redefining the meaning of const and overloading the invariant keyword with a second meaning? Or maybe words more like "watched", "witnessed", "espied" -- or maybe just "espy", I like that one -- meaning you can only look at the thing. All these words have no constancy connotation and I think they'd be much better for grasping the D concept of constancy. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michel Fortin wrote:
 But const in D 1.0 and D 2.0 doesn't mean the same thing does it?

Right.
 I 
 think using readonly for what is const in D 2.0 and const for what is 
 invariant makes more sense... although just like you I don't like much 
 the name "readonly" for that meaning: it looks too much like a synonym.

As I mentioned to Sean, "readonly" has a long history of meaning "nobody can write to it." We have ROMs (Read Only Memory) and virtual memory that has "Read Only" settings, etc. Redefining readonly this way is going to satisfy half the people, and confuse the hell out of everyone else. The thing about "const" is that the major language that uses it, C++, uses it most of the time with the meaning "read only view, but others can write to it." The other thing about "const" is that it gets written a lot, and (at least in C++) it tends to consume a lot of horizontal space. Using a longer keyword would be problematic.
 Ever thought of "shut", "guarded", "shielded", "occluded", or anything 
 else conceptualizing some kind of barrier instead of redefining the 
 meaning of const and overloading the invariant keyword with a second 
 meaning? Or maybe words more like "watched", "witnessed", "espied" -- or 
 maybe just "espy", I like that one -- meaning you can only look at the 
 thing. All these words have no constancy connotation and I think they'd 
 be much better for grasping the D concept of constancy.

We can (and essentially did) debate this forever. The bottom line is, it's just a word, and at some level it becomes the color of the bicycle shed problem.
Mar 28 2008
next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el 28 de marzo a las 11:20 me escribiste:
 We can (and essentially did) debate this forever. The bottom line is, it's
just a word, and at some level it becomes the color of the bicycle shed problem.

I think Sean is right about this one. It's not a color problem, is like change the bicycle breaks to make it turn right. You are changing the meaning of a previous (well known and pretty reasonable) keyword. Which seems a little arbitrary and risky. BTW, "view" makes perfect sense for D2.0 "const" semantics... -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Home, home again. I like to be here when I can. When I come home cold and tired It's good to warm my bones beside the fire.
Mar 28 2008
prev sibling next sibling parent reply Roberto Mariottini <rmariottini mail.com> writes:
Walter Bright wrote:
 Michel Fortin wrote:
 But const in D 1.0 and D 2.0 doesn't mean the same thing does it?

Right.

OK, finally I understand what the big "const problem" is: the keyword 'const' changed meaning from D 1.x to D2.x, and ... [...]
 The thing about "const" is that the major language that uses it, C++, 
 uses it most of the time with the meaning "read only view, but others 
 can write to it." The other thing about "const" is that it gets written 
 a lot, and (at least in C++) it tends to consume a lot of horizontal 
 space. Using a longer keyword would be problematic.

... and in D2.x it took the same meaning of C++ 'const'. The solution is simple: remove 'const' from the keywords. Moreover, 'const' is not an English word: is an abbreviation of 'constant'. Another reason for dropping 'const' is that it's used in Pascal. [...]
 We can (and essentially did) debate this forever. The bottom line is, 
 it's just a word, and at some level it becomes the color of the bicycle 
 shed problem.

The "Bicycle Shed Problem" is the most important still open problem in Computer Science. Let's try to resolve it here: vote another abbreviation of 'constant'. 1) c 2) co 3) cn 4) cs 5) ct 6) con 7) cns 8) cnt 9) cnn 10) cst 11) csn 12) ctt 13) cons 14) cnst 15) cstn 16) cnnt 17) csnt 19) cnstn 20) cstnt 21) cntnt 22) consta 23) cnstnt 24) contnt 25) costnt 26) consnt 27) constan 28) cnstant 29) costant 30) contant 31) consant 32) constnt 33) constat 34) constant You can cast any number of votes. My vote is for 1, 9, 22, 23, 29, 33 and 34. Ciao -- Roberto Mariottini, http://www.mariottini.net/roberto/ SuperbCalc, a free tape calculator: http://www.mariottini.net/roberto/superbcalc/
Mar 31 2008
parent reply Jason House <jason.james.house gmail.com> writes:
I still think any keyword change should improve understandability. Given
history on this mailing list, I first think of 'read only view'. Maybe rov or
read. I like read best, but it'll conflict with libraries. Allowing read as a
member function is doable, but I doubt Walter would want the extra complexity.

Roberto Mariottini Wrote:

 Walter Bright wrote:
 Michel Fortin wrote:
 But const in D 1.0 and D 2.0 doesn't mean the same thing does it?

Right.

OK, finally I understand what the big "const problem" is: the keyword 'const' changed meaning from D 1.x to D2.x, and ... [...]
 The thing about "const" is that the major language that uses it, C++, 
 uses it most of the time with the meaning "read only view, but others 
 can write to it." The other thing about "const" is that it gets written 
 a lot, and (at least in C++) it tends to consume a lot of horizontal 
 space. Using a longer keyword would be problematic.

... and in D2.x it took the same meaning of C++ 'const'. The solution is simple: remove 'const' from the keywords. Moreover, 'const' is not an English word: is an abbreviation of 'constant'. Another reason for dropping 'const' is that it's used in Pascal. [...]
 We can (and essentially did) debate this forever. The bottom line is, 
 it's just a word, and at some level it becomes the color of the bicycle 
 shed problem.

The "Bicycle Shed Problem" is the most important still open problem in Computer Science. Let's try to resolve it here: vote another abbreviation of 'constant'. 1) c 2) co 3) cn 4) cs 5) ct 6) con 7) cns 8) cnt 9) cnn 10) cst 11) csn 12) ctt 13) cons 14) cnst 15) cstn 16) cnnt 17) csnt 19) cnstn 20) cstnt 21) cntnt 22) consta 23) cnstnt 24) contnt 25) costnt 26) consnt 27) constan 28) cnstant 29) costant 30) contant 31) consant 32) constnt 33) constat 34) constant You can cast any number of votes. My vote is for 1, 9, 22, 23, 29, 33 and 34. Ciao -- Roberto Mariottini, http://www.mariottini.net/roberto/ SuperbCalc, a free tape calculator: http://www.mariottini.net/roberto/superbcalc/

Mar 31 2008
next sibling parent Yigal Chripun <yigal100 gmail.com> writes:
Janice Caron wrote:
 On 31/03/2008, Jason House <jason.james.house gmail.com> wrote:
   
 Maybe rov or read.
     

Again, "readable" doesn't imply "not writeable". (It is perfectly possible for a thing to be both readable and writeable at the same time). Let's just stick with "in". It's /already implemented/ in one of the places where it's needed, and let's face it, keywords don't get much shorter!

just to throw my 2 cents to the mix: i don't like "in" as it doesn't mean "read only view" and for a line like : in(int) temp = 1; that's just looks strange to me. the stated benefits of using it as stated by others are the fact that it's already in the language, and it's short. instead of looking at current "const" meaning as read only view, you could say it's means "protected". a protected variable is such a variable that is protected from writing. the word "protected" itself is too long for my personal taste, so here's a list of other possibilities: - shielded (I've seen this on someone else's post) - sealed (used in c#) - protected (too long IMO) - final (already reserved in D) <- i like this one as it's the same length as const, already in D, etc.. - perm[anent] - fixed etc... Personally, I think "in" should be deprecated. no need to have two reserved words that do the same thing (if it currently means const, why should I bother using const which is longer? ) const should replace invariant (I agree with everyone else that invariant breaks the meaning of const in D1, and it's long) also, in my ideal world, functions would be rewritten with the return type at the end: someFunc(...param list...) returnType; but I'd settle for: final(this) returnType someFunc(...param list...); one last thing: since D const != C/C++ const (transitivity and such) than the D syntax for it shouldn't try to be backward compatible to C/C++. that's just confusing. a good example of that is : const const int func(params..); that's bad. i'd prefer that the syntax const(T) would be mandatory. -- Yigal
Mar 31 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Janice Caron Wrote:

 On 31/03/2008, Jason House <jason.james.house gmail.com> wrote:
 Maybe rov or read.

Again, "readable" doesn't imply "not writeable". (It is perfectly possible for a thing to be both readable and writeable at the same time).

That's like saying "in" doesn't imply "not out". While true, it really isn't what people initially assume. I like readonly better than read, but we already know walter believes readonly means nobody can write and so isn't an option.
 Let's just stick with "in". It's /already implemented/ in one of the
 places where it's needed, and let's face it, keywords don't get much
 shorter!

As is the normal problem with picking keywords, you can't find one that everyone universally likes. Outside of function arguments, I don't like the use of the word "in". It also seems to assume that in meaning "const scope" is going away. I'm hoping that's not true, but I guess we'll see...
Mar 31 2008
parent Georg Wrede <georg nospam.org> writes:
Jason House wrote:
 Janice Caron Wrote:
 Let's just stick with "in". It's /already implemented/ in one of
 the places where it's needed, and let's face it, keywords don't get
 much shorter!

As is the normal problem with picking keywords, you can't find one that everyone universally likes. Outside of function arguments, I don't like the use of the word "in". It also seems to assume that in meaning "const scope" is going away. I'm hoping that's not true, but I guess we'll see...

I agree. With parameter lists, "in" seems appropriate for two reasons, neither of which apply outside of them: - Parameter lists are crowded as it is. A long word instead of "in" would exacerbate this unduely, and make it harder to see "at a glance" what's going on. - In does retain some of its English meaning there. Now, everywhere else, the latter meaning seems irrelevant. It could also be argued that "in" is too short to spot (which of course is excusable in parameter lists), and an important thing such as constness should really be denoted with something more conspicuous and deliberate. So, "in" outside of parameter lists is as relevant as id, ud, da, no, on, it, cc, etc... And saving keywords as an excuse, I'd rather count such as a counter-argument!
Mar 31 2008
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 31 Mar 2008 15:20:41 +0200, Janice Caron <caron800 googlemail.com>  
wrote:

 On 31/03/2008, Jason House <jason.james.house gmail.com> wrote:
 Maybe rov or read.

Again, "readable" doesn't imply "not writeable". (It is perfectly possible for a thing to be both readable and writeable at the same time). Let's just stick with "in". It's /already implemented/ in one of the places where it's needed, and let's face it, keywords don't get much shorter!

I have to say I really dislike 'in'. It's ok in a function parameter list, but what the hell is 'in(int)' supposed to look like? It certainly does not tell me anything about constancy (until I look it up, of course. But one should not depend on everyone looking up things all the time. Most people just want to sit down and program, not read manuals). 'const' and 'invariant' really are fine keywords to me, if the latter somewhat long. My only gripe with the current const system is 'enum', and I fear that will stay. 'pure', 'manifest', 'alias'... all those are great. But that's not really the topic at hand. --Simen
Mar 31 2008
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On 31/03/2008, Jason House <jason.james.house gmail.com> wrote:
 Maybe rov or read.

Again, "readable" doesn't imply "not writeable". (It is perfectly possible for a thing to be both readable and writeable at the same time).

But "read only view" does imply not writeable.
 Let's just stick with "in". It's /already implemented/ in one of the
 places where it's needed, and let's face it, keywords don't get much
 shorter!

"In" doesn't imply "not out". It also doesn't make much sense outside the context of a parameter. In what? For a regular variable calling it 'in' sounds like it would be write-only to me. As in "values can only go into the variable, not out." I like "rov" (or even just "ro" like some other language that's been mentioned here, but I suppose the "v" would have to be in there to appease Walter.) And while on the subject of "readonly", am I misreading this or is Walter basically the *only* one who thinks this sounds like it means "does not change ever". I think if you did a study asking programmers to rank the unchanging-ness of various const words, you'd get a result with "readonly" coming out much weaker than "constant". The fact that all the words mean effectively the same thing does not mean that everyone perceives the nuances in the same way. And if an overwhelming majority perceive "readonly" to have weaker meaning than "constant" or "invariant" it seems reasonable to choose that or some variation of it as the word that means the weaker form. --bb
Mar 31 2008
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Bill Baxter wrote:
 And while on the subject of "readonly", am I misreading this or is 
 Walter basically the *only* one who thinks this sounds like it means 
 "does not change ever".

pi is a constant. readonly is just a chmod from being writable.
Mar 31 2008
prev sibling next sibling parent Derek Parnell <derek nomail.afraid.org> writes:
On Tue, 01 Apr 2008 05:13:53 +0900, Bill Baxter wrote:

 Janice Caron wrote:
 On 31/03/2008, Jason House <jason.james.house gmail.com> wrote:
 Maybe rov or read.



For what its worth, I'm tending to think of 'const' as meaning 'constrained' rather than 'constant'. -- Derek (skype: derek.j.parnell) Melbourne, Australia 1/04/2008 3:20:42 PM
Mar 31 2008
prev sibling next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Janice Caron wrote:
 On 31/03/2008, Bill Baxter <dnewsgroup billbaxter.com> wrote:
  And while on the subject of "readonly", am I misreading this or is
  Walter basically the *only* one who thinks this sounds like it means
  "does not change ever".

I've never heard anyone but Walter make that claim.

Ditto. Come on, even non-programmers know what "read only access" means. I find it hard to believe there would be many people who'd have trouble grasping the idea that "read only" means "look but don't touch". Are there any languages where 'readonly' is used for putting values into ROM? Even if so, it doesn't seems like a difficult thing to unlearn. But look at the number of people on this NG for whom 'const' intuitively means 'constant, like pi'. Seriously, I think Walter's worrying about people who are fictional. The best argument for const IMHO is terminology. C++ programmers are used to talking about "const correctness". But since that's only logical const, it's not a strong argument; it creates false expectations. By the time D has the whole shebang with pure functions, we'll want to use our terminology anyway. And the name length is the second best argument.
 I, for one, would be /much/ happier with "readonly" or "ro" (or both -
 there's a thought), than "const", to mean "read only view"

Agreed.
Apr 02 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Don Clugston wrote:
 Ditto. Come on, even non-programmers know what "read only access" means.
 I find it hard to believe there would be many people who'd have trouble 
 grasping the idea that "read only" means "look but don't touch". Are 
 there any languages where 'readonly' is used for putting values into 
 ROM?

Yes, there are C extensions to do just that. Secondly, there is often hardware memory protection available, which has a "read only" bit. That means the data cannot be changed. Files marked "read only" cannot be written to by anyone. Read only has a long history of meaning immutable by anything, not just the viewer. "The readonly storage-class modifier, like the const data-type qualifier, assigns the NOWRT attribute to the variable's program section; if used with the static or globaldef specifier, the variable is stored in the $CODE psect, which has the NOWRT attribute by default." -- http://h71000.www7.hp.com/commercial/c/docs/5492profile_017.html
Apr 03 2008
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Walter Bright wrote:
 Don Clugston wrote:
 Ditto. Come on, even non-programmers know what "read only access" means.
 I find it hard to believe there would be many people who'd have 
 trouble grasping the idea that "read only" means "look but don't 
 touch". Are there any languages where 'readonly' is used for putting 
 values into ROM?

Yes, there are C extensions to do just that. Secondly, there is often hardware memory protection available, which has a "read only" bit. That means the data cannot be changed. Files marked "read only" cannot be written to by anyone. Read only has a long history of meaning immutable by anything, not just the viewer.

$ ls -l something -rw-r--r-- 1 gareis gareis 42 2008-02-27 18:14 something That file is readonly, unless you're me. And I'm free to change that. I don't find it compelling that some C extensions use readonly to put stuff in ROM, since C# is much more popular than probably all those C extensions combined and uses readonly to mean "cannot reassign outside a constructor".
Apr 03 2008
prev sibling parent Don Clugston <dac nospam.com.au> writes:
Walter Bright wrote:
 Don Clugston wrote:
 Ditto. Come on, even non-programmers know what "read only access" means.
 I find it hard to believe there would be many people who'd have 
 trouble grasping the idea that "read only" means "look but don't 
 touch". Are there any languages where 'readonly' is used for putting 
 values into ROM?

Yes, there are C extensions to do just that. Secondly, there is often hardware memory protection available, which has a "read only" bit. That means the data cannot be changed.

It's pretty common for the OS to load the exe into writable memory, then set the readonly bit. "read only" = the OS can write to it, but you can only read it. Ditto for files -- the administrator can always delete them. Files marked "read only" cannot be
 written to by anyone. Read only has a long history of meaning immutable 
 by anything, not just the viewer.
 
 "The readonly storage-class modifier, like the const data-type 
 qualifier, assigns the NOWRT attribute to the variable's program 
 section; if used with the static or globaldef specifier, the variable is 
 stored in the $CODE psect, which has the NOWRT attribute by default." -- 
 http://h71000.www7.hp.com/commercial/c/docs/5492profile_017.html
 

That looks pretty obscure to me. Besides, a paragraph later, that page describes const and readonly as pretty much synonymous: "For new program development, HP recommends that you use the const modifier, because const is standard-conforming and readonly is not." How often have you heard someone say "sorry, I only have read-only access to that directory?"
Apr 05 2008
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Bill Baxter" wrote
 And while on the subject of "readonly", am I misreading this or is Walter 
 basically the *only* one who thinks this sounds like it means "does not 
 change ever".  I think if you did a study asking programmers to rank the 
 unchanging-ness of various const words, you'd get a result with "readonly" 
 coming out much weaker than "constant".  The fact that all the words mean 
 effectively the same thing does not mean that everyone perceives the 
 nuances in the same way.  And if an overwhelming majority perceive 
 "readonly" to have weaker meaning than "constant" or "invariant" it seems 
 reasonable to choose that or some variation of it as the word that means 
 the weaker form.

Even in the context that Walter is thinking, most of the time ROM is writable. Think of BIOS ROM. At some point, someone has to write it :) I used to work with flash parts that were write once, and we considered those ROM chips. Which matches the meaning of const perfectly: "I can't write it, but something else can". I'm all for changing const to mean what invariant means, and using readonly or roview or rowhatever to mean what const means. -Steve
Apr 02 2008
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 
 And while on the subject of "readonly", am I misreading this or is 
 Walter basically the *only* one who thinks this sounds like it means 
 "does not change ever".  I think if you did a study asking programmers 
 to rank the unchanging-ness of various const words, you'd get a result 
 with "readonly" coming out much weaker than "constant".  The fact that 
 all the words mean effectively the same thing does not mean that 
 everyone perceives the nuances in the same way.  And if an overwhelming 
 majority perceive "readonly" to have weaker meaning than "constant" or 
 "invariant" it seems reasonable to choose that or some variation of it 
 as the word that means the weaker form.
 
 --bb

Yes! Exactly what I was about to say! My opinion, (and I'm sure, the opinion of many if not all of my programmer friends/colleagues, if I were to ask them) it that 'readonly' is a much weaker meaning than the other words. So the idea that "const, readonly, invariant, and immutable all mean exactly the same thing." is really just the opinion of Walter and a few either imaginary (like Don mentioned) or obsolete people. -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 26 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 05/04/2008, Don Clugston <dac nospam.com.au> wrote:
  That looks pretty obscure to me. Besides, a paragraph later...

  "For new program development, HP recommends that you use the const
  modifier [for invariant data], because const is standard-conforming and
 readonly  is not."

Ha! Walter, you are officially hoisted by your own petard! :-) Besides, ROM is only called ROM as a counterpoint to RAM. (ROM and RAM - it's cute!) Funny how no one ever suggests that "random access" be used as a synonym for "read/write". How about we invent the brand new coined word "ro", short for "borROwed", with the unambiguous meaning "I'm only borrowing this for a bit, so I promise not to damage it while it's in my possession". (The fact that "ro" could stand for other things is /entirely/ coincidental! :-))
Apr 05 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, renoX <renosky free.fr> wrote:
  I'd say that here both enum and const could be interesting:
  -const for 'traditional enum' and
  -enum for 'named' enumerated objects which you could print the name..

Ooh - I have a tonne of things to say about true enums. However, for the record, I was only talking about the use of the word "enum" as a const specified - i.e. enum x = 42; I wasn't suggesting that anything should happen to enum { a, b, c, d, e, f } Let's save that for another thread! :-)
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
Another alternative to view is viewof. As in viewof(T).

    void f(viewof(C));

or

    viewof(char)[]

etc. It's a tad longer than "veiw", but even so, that's now my
favorite one so far, just because of the way it looks and sounds in my
head.

Of course, it still looks weird when applied to member functions - but
then, so would anything, because of the confusing const-at-the-front
syntax we currently have:

    class C
    {
        viewof ReturnType f()
        {
            /*...*/
        }
    }

which only further reinforces my conviction that const-at-the-front
for member functions is the problem here, not the keyword for
constancy. The following is infinitely more readable:

    class C
    {
        viewof(this) ReturnType f()
    }

(The function f only gets a view of this). If we had viewof(this) for
member functions, and viewof(T) for types, then it would all be so
intuitive.
Mar 29 2008
prev sibling next sibling parent "Scott S. McCoy" <tag cpan.org> writes:
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


I don't think types should consist of compound phrases.  viewof sounds
like a method name, not a part of the primitive type system.  If you
forget about the existing const in D 1, const beats out viewof on
several counts:

 1. It's 1 character shorter.  We call it int and not integer for a
reason.
 2. It's one word
 3. It doesn't have a phrase which infers it's some form of translation
viewof(Type) looks like you're creating a view of a type.

That being said, I'm sort of annoyed with the fact that const(type)
looks like a function.  And I'm similarly annoyed with the introduction
of special syntax just so we can use the same phrase to classify methods
that we use to classify storage.  I mean, it makes sense from the
standpoint of static, but it doesn't make sense form the point that
const can be a return value.

const const(Foo) foo (const Foo).

That's just terrible.

From one angle, it makes sense following the form of static:

private static int _foo; public static int foo () { return _foo; } However it's not as natural, since the static keyword is behaving precisely the same in both of the above expressions. When you get to const, it stops behaving the same...that is.. class Foo { private const int _foo = 123; public const int foo () { return _foo; } } If I understand the D 2.0 specification as it sits now, these two const statements have nothing to do with each other, and that's the anomaly. In the static case a static method has to be static to access a static member value. But in the const case, the const method has nothing to do with the const member value. methods don't have to be const to access const member values, and vice verse. So that const only qualifies that you can call foo() in the instance of a const(Foo), which is defined as follows (assuming I understand correctly): const Foo foo = new Foo(); foo.foo(); So what we've done, it seems...is taken a syntax for one behavioral class, and applied it to another behavioral class. And because this has been done, to retain the constivity of int the above class is invalid, and you actually must: class Foo { private const int _foo = 123; public const const(int) foo () { return _foo; } } So what I'm saying I guess is, I feel like the current syntax is kind of messed up. I don't care about the keyword, but I do think const is better than viewof (although "view" might make more sense, but it really doesn't matter what it's called). So with that being the case, what if const was a type annotation. That is, what if a more annotative syntax was applied to make a given identifier const: private int : const foo; Either that, or what if atleast to rid ourselves of the disparity, the const storage class syntax was removed and replaced with that which is similar to the return value... The reason I say disparity, is my understanding is that const on a method only verifies that no values are modified via the this reference...so I think that means you're completely allowed to: class Foo { private int _foo = 123; public const int foo () { return _foo; } } So what if we atleast made the syntaxes consistent between storage and return values, forcibly: private const(int) foo; /* You have to say it's const(int).... */ public const const(int) foo () { return _foo; } /* Now atleast the syntax between the declaration of the identifier and the return value are consistent */ Similarly, you could always bring back the C++ish method classifications (they're still around, right?) public const: const int foo () { } const int bar () { } I don't find them that terrible...so now we have to define const method types within a special area in the class...that's actually not a bad idea anyway! But I'm sure it'll get some blowback. But I'm not totally convinced this is a concept that deserves only a new definition of an old keyword. Some special syntax seem in order. Never forget, we introduce punctuation to provide segmentation of concept. We do the same thing in programming languages...maybe some new punctuation is needed to provide a difference between const the member class and const the storage class. I dunno, just some ideas. My beef with const right now isn't the concept, it's great to have transitivity in const (assuming I understand it correctly) and hell, adds a lot of power to D for multiprogramming. Honestly, I don't think nearly as much is gained by having invariants and have wonder if they provide more than an optimization opportunity for the compiler. But still, I think the syntax could use some work. It feels a little hob-gobbled. I'm sure there is a much more expressive way to do this that I haven't thought of or mentioned in this email, but I'm pretty sure whatever it is we're not doing it. Cheers, Scott S. McCoy On Sun, 2008-03-30 at 07:58 +0100, Janice Caron wrote:
 
 
 
 
 Another alternative to view is viewof. As in viewof(T).
 

Mar 30 2008
prev sibling parent "Scott S. McCoy" <tag cpan.org> writes:
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


I don't think types should consist of compound phrases.  viewof sounds
like a method name, not a part of the primitive type system.  If you
forget about the existing const in D 1, const beats out viewof on
several counts:

 1. It's 1 character shorter.  We call it int and not integer for a
reason.
 2. It's one word
 3. It doesn't have a phrase which infers it's some form of translation
viewof(Type) looks like you're creating a view of a type.

That being said, I'm sort of annoyed with the fact that const(type)
looks like a function.  And I'm similarly annoyed with the introduction
of special syntax just so we can use the same phrase to classify methods
that we use to classify storage.  I mean, it makes sense from the
standpoint of static, but it doesn't make sense form the point that
const can be a return value.

const const(Foo) foo (const Foo).

That's just terrible.

From one angle, it makes sense following the form of static:

private static int _foo; public static int foo () { return _foo; } However it's not as natural, since the static keyword is behaving precisely the same in both of the above expressions. When you get to const, it stops behaving the same...that is.. class Foo { private const int _foo = 123; public const int foo () { return _foo; } } If I understand the D 2.0 specification as it sits now, these two const statements have nothing to do with each other, and that's the anomaly. In the static case a static method has to be static to access a static member value. But in the const case, the const method has nothing to do with the const member value. methods don't have to be const to access const member values, and vice verse. So that const only qualifies that you can call foo() in the instance of a const(Foo), which is defined as follows (assuming I understand correctly): const Foo foo = new Foo(); foo.foo(); So what we've done, it seems...is taken a syntax for one behavioral class, and applied it to another behavioral class. And because this has been done, to retain the constivity of int the above class is invalid, and you actually must: class Foo { private const int _foo = 123; public const const(int) foo () { return _foo; } } So what I'm saying I guess is, I feel like the current syntax is kind of messed up. I don't care about the keyword, but I do think const is better than viewof (although "view" might make more sense, but it really doesn't matter what it's called). So with that being the case, what if const was a type annotation. That is, what if a more annotative syntax was applied to make a given identifier const: private int : const foo; Either that, or what if atleast to rid ourselves of the disparity, the const storage class syntax was removed and replaced with that which is similar to the return value... The reason I say disparity, is my understanding is that const on a method only verifies that no values are modified via the this reference...so I think that means you're completely allowed to: class Foo { private int _foo = 123; public const int foo () { return _foo; } } So what if we atleast made the syntaxes consistent between storage and return values, forcibly: private const(int) foo; /* You have to say it's const(int).... */ public const const(int) foo () { return _foo; } /* Now atleast the syntax between the declaration of the identifier and the return value are consistent */ Similarly, you could always bring back the C++ish method classifications (they're still around, right?) public const: const int foo () { } const int bar () { } I don't find them that terrible...so now we have to define const method types within a special area in the class...that's actually not a bad idea anyway! But I'm sure it'll get some blowback. But I'm not totally convinced this is a concept that deserves only a new definition of an old keyword. Some special syntax seem in order. Never forget, we introduce punctuation to provide segmentation of concept. We do the same thing in programming languages...maybe some new punctuation is needed to provide a difference between const the member class and const the storage class. I dunno, just some ideas. My beef with const right now isn't the concept, it's great to have transitivity in const (assuming I understand it correctly) and hell, adds a lot of power to D for multiprogramming. Honestly, I don't think nearly as much is gained by having invariants and have wonder if they provide more than an optimization opportunity for the compiler. But still, I think the syntax could use some work. It feels a little hob-gobbled. I'm sure there is a much more expressive way to do this that I haven't thought of or mentioned in this email, but I'm pretty sure whatever it is we're not doing it. Cheers, Scott S. McCoy On Sun, 2008-03-30 at 07:58 +0100, Janice Caron wrote:
 
 
 
 
 Another alternative to view is viewof. As in viewof(T).
 

Mar 30 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, renoX <renosky free.fr> wrote:
  > I've suggested "view" in the past,

 I like it a lot: view as in 'view but don't touch' :-)

I like that one too. It's shorter than "readonly" as well, which is another big plus. Under that regime, my "ideal" would be in -> view const -> view invariant -> const enum -> const
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 31/03/2008, Bill Baxter <dnewsgroup billbaxter.com> wrote:
  And while on the subject of "readonly", am I misreading this or is
  Walter basically the *only* one who thinks this sounds like it means
  "does not change ever".

I've never heard anyone but Walter make that claim. In fact, Walter's argument (...we'll never find any set of words that everyone agrees on...) is your basic "divide and conquer" strategy. So long as any suggestion made is not unanimous, Walter can claim that as a reason for not going with it. In the case of "readonly", I suspect that we largely /are/ unanimous in thinking that it conveys the right impression, but then some would object because it's too long, and then we start going round in circles again, starting with "ro", which not everyone likes. I, for one, would be /much/ happier with "readonly" or "ro" (or both - there's a thought), than "const", to mean "read only view"
Mar 31 2008
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Sean Kelly wrote:
 
 This is why I've never understood the argument that a language must have
 as few keywords as it can get away with.  In my experience, having the same
 symbol represent multiple concepts tends to cause confusion.  The ideal
 situation is to have a simple syntax so only a few keywords are necessary,
 but barring that, I'd think that choosing an expressive and appropriate
 symbology for each situation would be best.  To me, it seems that the
 "minimize keyword count" idea began as a way to verify conceptual
 simplicity and has since become an arbitrary metric that measures
 nothing.
 
 
 Sean

The idea of minimizing keywords is because Walter said that there are people who look at the amount of keywords and find that too many keywords means that the language is cluttered and has a bad design. Seems like another case of caring to people who are either imaginary, obsolete, or just plain dumb. (like calling bugs 'issues', because some people think many bugs are synonymous with bad product quality) -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 26 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 31/03/2008, Jason House <jason.james.house gmail.com> wrote:
 Maybe rov or read.

Again, "readable" doesn't imply "not writeable". (It is perfectly possible for a thing to be both readable and writeable at the same time). Let's just stick with "in". It's /already implemented/ in one of the places where it's needed, and let's face it, keywords don't get much shorter!
Mar 31 2008
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright Wrote:
 I'm not so good at being a teacher,

Thank you for your long explanation. It seems you have done your best for D, and I respect that a lot. I'll try to understand the "const regime" again (especially when it's more debugged). If you are right, then eventually even dumb people like me will understand :-)
 Of course, if you're writing single-threaded one man programs of fairly 
 modest size, const is not particularly useful. I quite agree with that. 
 And in D you can effectively ignore const by just not using it, or by 
 using D 1.0. The only place const is imposed is with the immutable 
 string type.

Computer languages have to "scale", that usually means they have to "scale up", but making them able to "scale down" is useful too. Sometimes Java isn't much good at that "scaling down". Bye, bearophile
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 It seems you have done your best
 for D, and I respect that a lot.

Sometimes that means going against what the majority here wants. It's like being the CEO of a public corporation - do I do what's best for making the numbers look good for the next quarter, or do I do what's best for the long term future of the business?
Mar 27 2008
parent BCS <BCS pathlink.com> writes:
Walter Bright wrote:
 bearophile wrote:
 
 It seems you have done your best
 for D, and I respect that a lot.

Sometimes that means going against what the majority here wants. It's like being the CEO of a public corporation - do I do what's best for making the numbers look good for the next quarter, or do I do what's best for the long term future of the business?

And you can't know for sure what that is until it to late to do anything about it. So you learn all you can, ask the smartest people you can find and then guess.
Mar 27 2008
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:

 I understand your and others' frustration with const, and here's what I 
 think it is based on:
 [...]
 3) [...]
 In other words, not only do we need to explain how transitivity works in 
 particular in D, we have to explain what transitivity does and what it 
 is good for. For such a foreign concept, this is a tall order. I'm not 
 so good at being a teacher, I tend to explain how things work in D by 
 saying "it works just like X in language Y except with this little 
 tweak." I can't do that with transitive const. Andrei and I have spent 
 many, many hours sitting at a table with smart people explaining what 
 transitivity is. It is not an easy concept. Hey, I didn't get it for a 
 long time, either, which is partly why the first two const regimes in D 
 were wrong.

This is very true. I think you would have lost a lot fewer of us if there were some actual cohesive explanatory documentation of the latest design.
 4) The C++ const is ubiquitous and a lot of people are comfortable with 
 it, but it turns out that few understand what it guarantees and what it 
 doesn't. C++'s const is so weak that it is more of a convention than a 
 guarantee. This weakness enables things to be done with it that are just 
 fundamentally unsound, and contribute to C++ being a very difficult 
 language to write and verify sound code in.

Or maybe, despite the weaknesses it manages to cover 95% of cases that arise, and thus it represents a good trade-off between guarantees and ease-of-use.
 So, with all these things working against D const, there ought to be 
 some compelling reasons for us to swim against the tide and say it's 
 worth it:
 
 1. It makes function interfaces more self-documenting. Without 
 transitive const, for all pointer/reference parameters one must rely on 
 the documentation (which is always missing, out of date, or wrong). Note 
 that without transitivity, C++ const is nearly useless for such 
 self-documentation, which is why C++ programmers tend to rely on 
 convention instead.

That sounds almost completely wrong to me. C++ programmers tend to use 'const' in their function signatures to document the things that shouldn't change. That sounds like self-documentation to me. What do you mean by "rely on convention instead"? Please explain.
 2. It makes for interfaces that can be relied upon, which becomes 
 increasingly important the more people that are involved with the code. 
 In other words, it scales very well. People who are involved with 
 projects with large teams of programmers tell me that lack of const 
 makes their lives difficult because they cannot rely on the compiler to 
 enforce convention. The larger the team, the worse it gets. Managing 
 APIs is critical to a large project - it's why BASIC doesn't scale (for 
 an extreme example).

I dunno about this one. Java seems to scale pretty well. The long-standing enhancement request asking for const in Java was closed by Sun as "will not fix"[1]. They don't seem to think it's a show-stopper. [1] http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070
 3. Const transitivity makes for some interesting optimization 
 opportunities. The value of this has not been explored or exploited.

Opportunities are great. But asking everyone to eat their brussel sprouts for an indefinite amount of time because of some *potential* but not guaranteed future benefit is not going to get many people excited. If improved optimization is the goal then there are lots of opportunities for improvement in D's generation of FP code, for instance, or so I've heard. And those don't require any language changes. Even with fancy language features, can D really hope to compete against the likes of Intel and Microsoft or even GCC in the category of "best optimizer"?
 4. Here's the biggie. Points 1..3 are insignificant in comparison. The 
 future of programming will be multicore, multithreaded. Languages that 
 make it easy to program them will supplant languages that don't. 
 Transitive const is key to bringing D into this paradigm. The surge in 
 use of Haskell and Erlang is evidence of this coming trend (the killer 
 feature of those languages is they make it easy to do multiprogramming). 
 C++ cannot be retrofitted to supporting multiprogramming in a manner 
 that makes it accessible. D isn't there yet, but it will be, and 
 transitive const will be absolutely fundamental to making it work.

Again talk about potential is great, but until I've seen something more concrete I'm very skeptical that adding a dash of invariant into the mix is magically going to make D a multi-core champion. I suspect it will require very careful use of invariant in the parts of code you want to make parallel, and so it won't be just a magical switch that suddenly makes all your code run 10x faster. It'll be something that requires careful planning to take advantage of. I'm also doubly skeptical because if easy parallelism was the goal, an implementation of something akin to OpenMP should be possible even in D1.0. It doesn't require const/invariant. OpenMP works fine with C. It may not do everything that's possible in the grand vision, and may require more user intervention to employ, but it doesn't get much simpler than slapping a "#pragma pfor" in front of a for loop and having it automatically parallelized. And probably a lot of the thread management infrastructure would be similar to what is required by any grand vision anyway. So it wouldn't be wasted effort, I don't think.
 Of course, if you're writing single-threaded one man programs of fairly 
 modest size, const is not particularly useful. I quite agree with that. 
 And in D you can effectively ignore const by just not using it, or by 
 using D 1.0. The only place const is imposed is with the immutable 
 string type.

"Just use 1.0" is only a temporary solution. You have to phase out D1.0 at some point. D is niche enough already without the dilution of having two major, incompatible versions. And arguments to just ignore const don't really work due to the viral nature of const. If you want to use a const-correct library, you will notice it when the library returns a const something to you, and you find you can't do anything with it unless you cast away const. But then you've entered into undefined territory and your program can no longer be considered correct. If you're a library writer then there will be pressure on you to make your libraries const-correct. Therefore most libraries will eventually end up being const-correct, and people who want to ignore const will have very few alternatives. I've seen very few C++ libraries that don't at least try to be const-correct. For "just ignore const" to be a realistic recommendation there would need to be a "just ignore const" switch in the compiler. --bb
Mar 27 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 Walter Bright wrote:
 4) The C++ const is ubiquitous and a lot of people are comfortable 
 with it, but it turns out that few understand what it guarantees and 
 what it doesn't. C++'s const is so weak that it is more of a 
 convention than a guarantee. This weakness enables things to be done 
 with it that are just fundamentally unsound, and contribute to C++ 
 being a very difficult language to write and verify sound code in.

Or maybe, despite the weaknesses it manages to cover 95% of cases that arise, and thus it represents a good trade-off between guarantees and ease-of-use.

That is true looking backwards. But C++ const is no good for the future, and this will become more and more apparent. C++'s troubles with multiprogramming are just beginning.
 1. It makes function interfaces more self-documenting. Without 
 transitive const, for all pointer/reference parameters one must rely 
 on the documentation (which is always missing, out of date, or wrong). 
 Note that without transitivity, C++ const is nearly useless for such 
 self-documentation, which is why C++ programmers tend to rely on 
 convention instead.

That sounds almost completely wrong to me. C++ programmers tend to use 'const' in their function signatures to document the things that shouldn't change. That sounds like self-documentation to me. What do you mean by "rely on convention instead"? Please explain.

First, it's legal to cast away const and then change the underlying data. This is frowned on by convention, but it's *legal*. Second, and much worse, consider: void foo(const T& t) { ... } what does that tell you? That t's value won't be changed by foo(). Ok. But what if T is a tree data structure? const tells you NOTHING AT ALL about the mutability of that structure. foo() can rewrite everything in that tree but the root node. EVERYTHING, and it's all perfectly legal without even having to resort to casting. This is, of course, frowned upon by convention, but it's nothing more than convention. It's about as effective as annotating t with a comment: /*doesn't change any part of T*/ Now, you could go through the components of T and mark them all const, too, but that doesn't work if T is an opaque type (opaque types are becoming more and more important as an encapsulation device). The beauty of transitive const is that everything reachable through t cannot be modified by going through t, and this will be true regardless of whether T is opaque or transparent.
 2. It makes for interfaces that can be relied upon, which becomes 
 increasingly important the more people that are involved with the 
 code. In other words, it scales very well. People who are involved 
 with projects with large teams of programmers tell me that lack of 
 const makes their lives difficult because they cannot rely on the 
 compiler to enforce convention. The larger the team, the worse it 
 gets. Managing APIs is critical to a large project - it's why BASIC 
 doesn't scale (for an extreme example).

I dunno about this one. Java seems to scale pretty well. The long-standing enhancement request asking for const in Java was closed by Sun as "will not fix"[1]. They don't seem to think it's a show-stopper. [1] http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070

Java can't fix it and be backwards compatible. They're stuck. If they had a chance of a do-over, I have little doubt they'd go for transitive const. The pressure to add const to Java comes up again and again. It's not going to go away, and it's just going to get worse. Java missed the boat on multiprogramming, too (it's not in as bad a shape there as C++, but Java's design is still based on an obsolete view of how to do multiprogramming). C++0x is trying to catch up with Java, but Java is way behind functional languages. It's like the man with no legs trying to catch the man hopping on one leg, while the man with two runs away from both of them.
 3. Const transitivity makes for some interesting optimization 
 opportunities. The value of this has not been explored or exploited.

Opportunities are great. But asking everyone to eat their brussel sprouts for an indefinite amount of time because of some *potential* but not guaranteed future benefit is not going to get many people excited.

A lot of people are excited about C++0x, which is still many years away. In fact, a lot people say C++0x is why they won't use D which has those features today.
 If improved optimization is the goal then there are lots of 
 opportunities for improvement in D's generation of FP code, for 
 instance, or so I've heard.  And those don't require any language 
 changes.  Even with fancy language features, can D really hope to 
 compete against the likes of Intel and Microsoft or even GCC in the 
 category of "best optimizer"?

I agree the optimization capability isn't a compelling reason by itself.
 4. Here's the biggie. Points 1..3 are insignificant in comparison. The 
 future of programming will be multicore, multithreaded. Languages that 
 make it easy to program them will supplant languages that don't. 
 Transitive const is key to bringing D into this paradigm. The surge in 
 use of Haskell and Erlang is evidence of this coming trend (the killer 
 feature of those languages is they make it easy to do 
 multiprogramming). C++ cannot be retrofitted to supporting 
 multiprogramming in a manner that makes it accessible. D isn't there 
 yet, but it will be, and transitive const will be absolutely 
 fundamental to making it work.

Again talk about potential is great, but until I've seen something more concrete I'm very skeptical that adding a dash of invariant into the mix is magically going to make D a multi-core champion. I suspect it will require very careful use of invariant in the parts of code you want to make parallel, and so it won't be just a magical switch that suddenly makes all your code run 10x faster. It'll be something that requires careful planning to take advantage of.

I fully agree that invariant by itself doesn't magically turn D into a multiprogrammer's dream. But invariant is a crucial brick in building multiprogramming support. The lack of it is why C++ will never be easy to use for multiprogramming. We're just on the cusp of a huge push towards multiprogramming. We have to be ready for it, or we'll be left in the dustbin of history.
 I'm also doubly skeptical because if easy parallelism was the goal, an 
 implementation of something akin to OpenMP should be possible even in 
 D1.0.  It doesn't require const/invariant.  OpenMP works fine with C. It 
 may not do everything that's possible in the grand vision, and may 
 require more user intervention to employ, but it doesn't get much 
 simpler than slapping a "#pragma pfor" in front of a for loop and having 
 it automatically parallelized.  And probably a lot of the thread 
 management infrastructure would be similar to what is required by any 
 grand vision anyway.  So it wouldn't be wasted effort, I don't think.

OpenMP is a massive kludge. I don't believe that is where the future lies.
 Of course, if you're writing single-threaded one man programs of 
 fairly modest size, const is not particularly useful. I quite agree 
 with that. And in D you can effectively ignore const by just not using 
 it, or by using D 1.0. The only place const is imposed is with the 
 immutable string type.

"Just use 1.0" is only a temporary solution. You have to phase out D1.0 at some point.

It'll get phased out when it no longer has a user base.
 D is niche enough already without the dilution of having 
 two major, incompatible versions.
 
 And arguments to just ignore const don't really work due to the viral 
 nature of const.  If you want to use a const-correct library, you will 
 notice it when the library returns a const something to you, and you 
 find you can't do anything with it unless you cast away const.  But then 
 you've entered into undefined territory and your program can no longer 
 be considered correct.  If you're a library writer then there will be 
 pressure on you to make your libraries const-correct.  Therefore most 
 libraries will eventually end up being const-correct, and people who 
 want to ignore const will have very few alternatives.  I've seen very 
 few C++ libraries that don't at least try to be const-correct.
 
 For "just ignore const" to be a realistic recommendation there would 
 need to be a "just ignore const" switch in the compiler.

As far as library writing goes, you're right that you cannot ignore const. But application writers pretty much can, as I pretty much ignore const in C++.
Mar 27 2008
parent reply Georg Wrede <georg nospam.org> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 Again talk about potential is great, but until I've seen something 
 more concrete I'm very skeptical that adding a dash of invariant 
 into the mix is magically going to make D a multi-core champion.  I
  suspect it will require very careful use of invariant in the parts
  of code you want to make parallel, and so it won't be just a 
 magical switch that suddenly makes all your code run 10x faster. 
 It'll be something that requires careful planning to take advantage
  of.

I fully agree that invariant by itself doesn't magically turn D into a multiprogrammer's dream. But invariant is a crucial brick in building multiprogramming support. The lack of it is why C++ will never be easy to use for multiprogramming. We're just on the cusp of a huge push towards multiprogramming. We have to be ready for it, or we'll be left in the dustbin of history.

I massively agree here. While I've said that I personally don't use const, I still think pursuing const, const-correctness, and const transitivity are definitely a top priority for D. My take on it is, _because_ const transitivity is _hard_ to patch onto C++, Java, etc., _and_ it seems to be within reach for D, that alone is reason enough to give it our best shot. (If it turns out later that not even we can do it, then so be it. But 5 years from now, we'd crucify ourselves for not having tried, if it turns out it's been done in any of those languages, even half-bakedly.) And, once we get it right, I'd be surprised if not almost everyone here starts using it as a matter of course. When it works and is not unduely obtrusive to use, I think most would agree that it's the Right Thing to do, even in small projects. (Using the same MO everywhere is easier than up front deciding wether this'll be a big or a small project.) Plus, when teaching classes, const would then be taught right after the concept of functions, and way before recursion or linked lists. === mostly off-topic ===
 The long-standing enhancement request asking for const in Java was 
 closed by Sun as "will not fix"[1].  They don't seem to think it's 
 a show-stopper.
 
 [1] http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070

Java can't fix it and be backwards compatible. They're stuck. If they had a chance of a do-over, I have little doubt they'd go for transitive const. The pressure to add const to Java comes up again and again. It's not going to go away, and it's just going to get worse.

Since Java is only on a VM (the last physical CPU to run Java natively was, I guess, my Java Ring that I got from a convention, years ago...), it is interesting that they didn't run multithread stuff already in the nineties on a regular basis to get experience on multithreading. How hard can it be to write a two- or even eight-virtual-processor VM? Basically all you need is a 386 (albeit "overclocked"). The VM would of course fake the multi thing, but still. Would've given them a head start.
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Georg Wrede wrote:
 Walter Bright wrote:
 We're just on the cusp of a huge push towards multiprogramming. We 
 have to be ready for it, or we'll be left in the dustbin of history.

I massively agree here. While I've said that I personally don't use const, I still think pursuing const, const-correctness, and const transitivity are definitely a top priority for D. My take on it is, _because_ const transitivity is _hard_ to patch onto C++, Java, etc., _and_ it seems to be within reach for D, that alone is reason enough to give it our best shot. (If it turns out later that not even we can do it, then so be it. But 5 years from now, we'd crucify ourselves for not having tried, if it turns out it's been done in any of those languages, even half-bakedly.)

That cusp means that people are (even now) leaving C++ and Java and looking for multiprogramming languages. This is going to soon turn into a flood. This is a major window of opportunity for D. Haskell and Erlang are the current beneficiaries of that, and C++0x has a rather mad scramble going on just to acknowledge the existence of multiprogramming in the Standard.
 Since Java is only on a VM (the last physical CPU to run Java natively 
 was, I guess, my Java Ring that I got from a convention, years ago...), 
 it is interesting that they didn't run multithread stuff already in the
 nineties on a regular basis to get experience on multithreading.
 
 How hard can it be to write a two- or even eight-virtual-processor VM?
 Basically all you need is a 386 (albeit "overclocked"). The VM would of
 course fake the multi thing, but still.
 
 Would've given them a head start.

People were doing multiprogramming with Java from the beginning. That's why it has synchronized functions, volatile, etc. The thing is, we have 10 more years of experience with what works and what doesn't work with multiprogramming, so we can do a much better job.
Mar 27 2008
parent Georg Wrede <georg nospam.org> writes:
Walter Bright wrote:
 People were doing multiprogramming with Java from the beginning. That's 
 why it has synchronized functions, volatile, etc. The thing is, we have 
 10 more years of experience with what works and what doesn't work with 
 multiprogramming, so we can do a much better job.

At the time I never thought of multiple CPUs. Looks like "neither did they". Nothing in the examples or discussions specifically led one to think we're actually talking about several processors. (I guess it may have been implied, but in that case the thought would've been that that'll come in the "distant" future.) Somehow the thought was that one should consider multithreading as if it happened on several processors, but that in "reality" it'll be implemented on a single processor just hopping between the threads -- not that you should make big deal about it: the code you write should still be the same anyway. For that, using Java's Synchronized etc., seemed adequate, both for a 1-CPU and for an N-CPU hardware. But what they should have done is really investigate the issues /between/ multithreading and multiprocessor scenarios. And precisely that should have been easy with the multi-virtual-CPU-Java-VM. And given then the head start they'd needed. While I'm at it, in the late '90s, I organised a Java seminar in Lapland. I got some of the best academic and free-lance speakers available, to speak on Advanced Java Concepts to the best programmers in several of the largest corporations around, while still addressing the audience as if they hadn't too many years of Java experience. (Which they couldn't have since Java had only _been_around_ for a couple of years.) One of the lectures I'll never forget was about multithreading and Objects. While I in theory knew about multithreading, OOP, and had even done some multithreading OOP dabbling privately, this guy really opened my eyes. "Several threads may run the code of one object instance, simultaneously." "One object instance may run several threads, simultaneously." "Both of these may be true at any one time." No woman has ever made me as breathless. It took me weeks to fully grasp the essence of it.
Mar 27 2008
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2008-03-28 04:26:42 -0400, "Janice Caron" <caron800 googlemail.com> said:

 On 27/03/2008, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 That sounds almost completely wrong to me.  C++ programmers tend to use
 'const' in their function signatures to document the things that
 shouldn't change.  That sounds like self-documentation to me.  What do
 you mean by "rely on convention instead"? Please explain.

class C { int ** p; } void f(const C &c) { **c.p = 1; // Legal in C++ }

No, that's not legal in C++ because p is private (class members are private in C++ unless explicitly made public). But beside that, is legal.
 There is no way to express compiler-checked transitive constancy in C++.

There's a way if you really want it: keep the variable private and make sure the accessor functions return a pointer corresponding to the constancy you want, something like const int * const * getP() const { return p; } int ** getP() { return p; } That's all a manual task to get there though (error prone?), and you have to know about the type you're dealing with (which can be complicated in templates). -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Mar 28 2008
prev sibling next sibling parent reply Darryl Bleau <user example.net> writes:
Walter,

First, thank you very much for this detailed explanation. I know that I
have personally wondered what all the constant-fussing was about, and
and sure that this post serves to answer questions that others probably
share with me.


 In other words, not only do we need to explain how transitivity works in
 particular in D, we have to explain what transitivity does and what it
 is good for. For such a foreign concept, this is a tall order. I'm not
 so good at being a teacher, I tend to explain how things work in D by
 saying "it works just like X in language Y except with this little
 tweak." I can't do that with transitive const. Andrei and I have spent
 many, many hours sitting at a table with smart people explaining what
 transitivity is. It is not an easy concept. Hey, I didn't get it for a
 long time, either, which is partly why the first two const regimes in D
 were wrong.

Is there anyplace that does offer up an explanation? If there isn't, is there potentially someone that fully understands this transitive const situation that would be willing to write something up on this? Why it's important, how it would be used in real world, possibly with some concrete examples (A lot of these X(T) Y(Z : R) etc posts being made are great and all, but bringing some reality back down in there might help to convey understanding).
 4. Here's the biggie. Points 1..3 are insignificant in comparison. The
 future of programming will be multicore, multithreaded. Languages that
 make it easy to program them will supplant languages that don't.
 Transitive const is key to bringing D into this paradigm. The surge in
 use of Haskell and Erlang is evidence of this coming trend (the killer
 feature of those languages is they make it easy to do multiprogramming).
 C++ cannot be retrofitted to supporting multiprogramming in a manner
 that makes it accessible. D isn't there yet, but it will be, and
 transitive const will be absolutely fundamental to making it work.

Could you expand on how this would help? Is it as simple as being able to guarantee that certain data is not going to be altered, thusly removing any need for guard locks et al?
Mar 27 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Darryl Bleau (user example.net)'s article
 Walter,
 4. Here's the biggie. Points 1..3 are insignificant in comparison. The
 future of programming will be multicore, multithreaded. Languages that
 make it easy to program them will supplant languages that don't.
 Transitive const is key to bringing D into this paradigm. The surge in
 use of Haskell and Erlang is evidence of this coming trend (the killer
 feature of those languages is they make it easy to do multiprogramming).
 C++ cannot be retrofitted to supporting multiprogramming in a manner
 that makes it accessible. D isn't there yet, but it will be, and
 transitive const will be absolutely fundamental to making it work.

to guarantee that certain data is not going to be altered, thusly removing any need for guard locks et al?

Pretty much. The reason imperative languages tend to stink for this sort of thing is because programs written in these languages typically share data across processes (threads), which introduces the need for synchronization. I suspect the idea is that by shoehorning invariance into the everyday practice of programming (via 'string', etc) that we may be able to make applications more conducive to parallelization without actually altering the basic approach for writing applications. I'll admit to being a bit skeptical that this will actually be sufficient as a long- term solution, but it's worth a shot. Personally, my money is still on functional languages though. Sean
Mar 27 2008
parent Russell Lewis <webmaster villagersonline.com> writes:
Sean Kelly wrote:
 Pretty much.  The reason imperative languages tend to stink for this sort
 of thing is because programs written in these languages typically share
 data across processes (threads), which introduces the need for
 synchronization.  I suspect the idea is that by shoehorning invariance
 into the everyday practice of programming (via 'string', etc) that we
 may be able to make applications more conducive to parallelization
 without actually altering the basic approach for writing applications.  I'll
 admit to being a bit skeptical that this will actually be sufficient as a long-
 term solution, but it's worth a shot.  Personally, my money is still on
 functional languages though.

I'm mostly with you, but I am guessing that what will actually happen is a merging of the two. Functional languages are great for expressing "what" questions, while imperative languages are great for expressing "how". Neither does well in the other's area, IMHO. Having a compound language which allowed imperative programming for the sequence-heavy code and functional programming for the easily parallelizable code makes a lot of sense to me. I think that Walter is trying to push the language that way. It remains to be seen whether it will work or not, but it's a valiant effort.
Mar 27 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Darryl Bleau wrote:
 Could you expand on how this would help? Is it as simple as being able
 to guarantee that certain data is not going to be altered, thusly
 removing any need for guard locks et al?

I won't pretend I have any details worked out. But if you look at functional programming, a key reason why it's so well suited to multiprogramming is a function can be GUARANTEED that its arguments will not be altered asynchronously. Furthermore, you can GUARANTEE that one function has no timing dependencies on another function. The more that can be guaranteed, the less places there are for bugs to fester.
Mar 27 2008
parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el 27 de marzo a las 17:08 me escribiste:
 Darryl Bleau wrote:
Could you expand on how this would help? Is it as simple as being able
to guarantee that certain data is not going to be altered, thusly
removing any need for guard locks et al?

I won't pretend I have any details worked out. But if you look at functional programming, a key reason why it's so well suited to multiprogramming is a function can be GUARANTEED that its arguments will not be altered asynchronously. Furthermore, you can GUARANTEE that one function has no timing dependencies on another function.

The key in functional programming languages is their ability to know when a function don't have side effects (basically if you call a function with the same arguments, you'll get the same results, including the global state). When you don't have side effects you can easily implmente such things as transactional memory[1]. [1] http://en.wikipedia.org/wiki/Software_transactional_memory A nice video of Haskel implementation of STM: http://channel9.msdn.com/Showpost.aspx?postid=231495 -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- PADRES DENUNCIAN QUE SU HIJA SE ESCAPO CON UN PARAGUAYITO -- Crónica TV
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 27/03/2008, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 That sounds almost completely wrong to me.  C++ programmers tend to use
  'const' in their function signatures to document the things that
  shouldn't change.  That sounds like self-documentation to me.  What do
  you mean by "rely on convention instead"? Please explain.

class C { int ** p; } void f(const C &c) { **c.p = 1; // Legal in C++ } There is no way to express compiler-checked transitive constancy in C++.
Mar 28 2008
prev sibling next sibling parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
Walter Bright Wrote:

 1) We worked hard on what is the right way to do const for a year. This 
 included at least 3 very different implementations of const that were 
 released. The first two turned out to be very wrong and unworkable, and 
 we learned from that how to do it right. The problem is, we burned up a 
 lot of goodwill with it. Many people simply tuned out with "const is 
 bad". Many of the rest bring baggage from the previous const regimes 
 along that impair understanding of the current const regime.

You completely disregard the _real_ reason for people being hostile against the new const regime, in fact I think you are arrogant to the extreme; people are negative to the current regime because it is not good enough. You haven't burned a single ounce of goodwill with your various attempts - you have only showed that you are willing to let the community test the concepts. But now you have decided that you have found the "perfect", or at least best possible, solution - and while everyone agree that it is better than previous attempts, it is still not good enough for wide usage, or even medium usage. What the community need is a commitment to make the const system work, even if it requires even more changes - that is what a unstable compiler is for. If the const regime had been ready, you would most likely have seen a fairly massive surge of new users for D 2.0 - heck, we could even consider start porting Tango properly then. As it is now, I just have this icky feeling, going around hoping you will come around and make it work. Lars Ivar
Mar 28 2008
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Lars Ivar Igesund wrote:
 You completely disregard the _real_ reason for people being hostile against
the new const regime, in fact I think you are arrogant to the extreme; people
are negative to the current regime because it is not good enough. You haven't
burned a single ounce of goodwill with your various attempts - you have only
showed that you are willing to let the community test the concepts. But now you
have decided that you have found the "perfect", or at least best possible,
solution - and while everyone agree that it is better than previous attempts,
it is still not good enough for wide usage, or even medium usage. What the
community need is a commitment to make the const system work, even if it
requires even more changes - that is what a unstable compiler is for. 
 
 If the const regime had been ready, you would most likely have seen a fairly
massive surge of new users for D 2.0 - heck, we could even consider start
porting Tango properly then. As it is now, I just have this icky feeling, going
around hoping you will come around and make it work.

The post above states is a bit more strongly than I would prefer, but it somewhat reflects my view of the current state of const. To put things more gently, I think that what we have right now is an empirical (that is, experiment- and experience-based) understanding of const. The current const design seems to work pretty well with the cases that we've considered so far. But that was also true of C++'s const when it was designed, and to put it bluntly, it was true with the previous iterations of const in D. The previous iterations of const in D were shot down quickly on the NG because people posted (within a week or two) clear examples of glaring weaknesses in them. With our current const regime, the best we can say is, "we have not yet seen any clear examples of glaring weaknesses." Or, to be more honest, "the weaknesses which have been posted so far are things we are willing to live with." I don't have a lot of confidence that 10 years from now, or even 10 months from now, we won't be tearing const apart and rebuilding it, AGAIN. We're going to face this problem over and over, IMHO, until somebody can build up const from abstract first principles. Who are the users of const? (Library writers, ordinary coders, optimizers, etc.) What are the threats to const? (Synchronous function calls, asynchronous function calls (signal handlers and interrupts), multithreading, external devices (DMA), etc.?) What are the things that somebody might want to express (you can't modify, nobody will ever modify, nobody will modify in this window of time, logical const, copy-on-write semantics, somebody asynchronously *will* modify in this window, etc.) Until we have this fundamental, mathematical understanding of const, we are just tweaking and hacking and patching in hopes we can come up with something good enough.
Mar 28 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Russell Lewis wrote:
 Until we have this fundamental, mathematical understanding of const, we 
 are just tweaking and hacking and patching in hopes we can come up with 
 something good enough.

But the current const regime *is* based on a mathematical notion. The reason the previous regimes failed is not because the notion was wrong, but because we had tried to support some special use cases.
Mar 28 2008
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Walter Bright wrote:
 Russell Lewis wrote:
 Until we have this fundamental, mathematical understanding of const, 
 we are just tweaking and hacking and patching in hopes we can come up 
 with something good enough.

But the current const regime *is* based on a mathematical notion. The reason the previous regimes failed is not because the notion was wrong, but because we had tried to support some special use cases.

Are you referring to transitive const? If so, I agree that this is *one* forward step in the formalization of const. A very good, very important step. But it is not, alone, a complete analysis of all of the things I described above. Or am I missing something?
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Russell Lewis wrote:
 Walter Bright wrote:
 Russell Lewis wrote:
 Until we have this fundamental, mathematical understanding of const, 
 we are just tweaking and hacking and patching in hopes we can come up 
 with something good enough.

But the current const regime *is* based on a mathematical notion. The reason the previous regimes failed is not because the notion was wrong, but because we had tried to support some special use cases.

Are you referring to transitive const? If so, I agree that this is *one* forward step in the formalization of const. A very good, very important step. But it is not, alone, a complete analysis of all of the things I described above. Or am I missing something?

I guess I'm missing something you mean.
Mar 28 2008
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Walter Bright wrote:
 Russell Lewis wrote:
 Walter Bright wrote:
 Russell Lewis wrote:
 Until we have this fundamental, mathematical understanding of const, 
 we are just tweaking and hacking and patching in hopes we can come 
 up with something good enough.

But the current const regime *is* based on a mathematical notion. The reason the previous regimes failed is not because the notion was wrong, but because we had tried to support some special use cases.

Are you referring to transitive const? If so, I agree that this is *one* forward step in the formalization of const. A very good, very important step. But it is not, alone, a complete analysis of all of the things I described above. Or am I missing something?

I guess I'm missing something you mean.

What I've been thinking of late is that const is a multidimensional concept. Different types of const may have different answers to each of the following questions: * Who declares that this entity is "const"? - Compiler? - Library writer? - Ordinary coder? * Who is limited by it? - Compiler ("don't optimize")? - Caller? - Callee? * Who enforces it? - Compiler? - Programmer? - A combination? * Who is interested in it? - Compiler? - Programmer? - Other modules? - Maintainer trying to understand the code? * Who is entitled to make assumptions based on it? - Compiler optimizations? - Programmer assert()s and algorithms? - Other modules? * How long does it last? - Forever? - From here on out? - In this block? - So long as this pointer is valid? - Except when we call another function? - Almost always, except for certain windows? * What are we protecting? - Logical semantics? - Function return values? - Binary storage? * What if we want to modify this? - Perform COW? - Use thunks? (COW with shared result pointer) - Never modify it? So "const" is (at least) a 8-dimensional concept. When I talk a mathematical understanding of const, I mean that somebody needs to list out the various answers to the questions above (there probably are more than I listed) and formally examine each one. Also, find more questions. (When I first composed this email, I had 6 questions. Just in the last 10 minutes, the list expanded to 8 questions! ) What I'm hoping for is a system that either: A) Can express any arbitrary point in the above space, or B) Makes convincing arguments why some of those points are unnecessary. Overkill? Perhaps. But we've tried repeatedly to make const work, and what we've learned is that "const is subtle, and hard to get right." More to the point, as we move into uncharted territory (such as trying to use "pure" functions and such for efficient multithreading), I am worried that some of the points in the space above (which seemed meaningless to our imperative-programming-trained brains) are going to become suddenly important. What do we do, then?
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Russell Lewis wrote:
 What I've been thinking of late is that const is a multidimensional 
 concept.  Different types of const may have different answers to each of 
 the following questions:
 
     * Who declares that this entity is "const"?
         - Compiler?
         - Library writer?
         - Ordinary coder?
     * Who is limited by it?
         - Compiler ("don't optimize")?
         - Caller?
         - Callee?
     * Who enforces it?
         - Compiler?
         - Programmer?
         - A combination?
     * Who is interested in it?
         - Compiler?
         - Programmer?
         - Other modules?
         - Maintainer trying to understand the code?
     * Who is entitled to make assumptions based on it?
         - Compiler optimizations?
         - Programmer assert()s and algorithms?
         - Other modules?
     * How long does it last?
         - Forever?
         - From here on out?
         - In this block?
         - So long as this pointer is valid?
         - Except when we call another function?
         - Almost always, except for certain windows?
     * What are we protecting?
         - Logical semantics?
         - Function return values?
         - Binary storage?
     * What if we want to modify this?
         - Perform COW?
         - Use thunks? (COW with shared result pointer)
         - Never modify it?
 
 So "const" is (at least) a 8-dimensional concept.  When I talk a 
 mathematical understanding of const, I mean that somebody needs to list 
 out the various answers to the questions above (there probably are more 
 than I listed) and formally examine each one.  Also, find more 
 questions.  (When I first composed this email, I had 6 questions.  Just 
 in the last 10 minutes, the list expanded to 8 questions! )
 
 What I'm hoping for is a system that either:
 A) Can express any arbitrary point in the above space,
     or
 B) Makes convincing arguments why some of those points are unnecessary.

I think all these have been answered, although not all in one place.
 Overkill?  Perhaps.  But we've tried repeatedly to make const work, and 
 what we've learned is that "const is subtle, and hard to get right." 
 More to the point, as we move into uncharted territory (such as trying 
 to use "pure" functions and such for efficient multithreading), I am 
 worried that some of the points in the space above (which seemed 
 meaningless to our imperative-programming-trained brains) are going to 
 become suddenly important.  What do we do, then?

We know what we want to do with const, it was just hard getting it worked in correctly to the existing language semantics.
Mar 28 2008
parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright wrote:
 We know what we want to do with const, it was just hard getting it
 worked in correctly to the existing language semantics.

Who's we?
Mar 28 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 Walter Bright wrote:
 We know what we want to do with const, it was just hard getting it
 worked in correctly to the existing language semantics.

Who's we?

I've laid it out several times; there's little object to the goals, just the method.
Mar 28 2008
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Russell Lewis wrote:
 We're going to face this problem over and over, IMHO, until somebody can 
 build up const from abstract first principles.  [...]
 
 Until we have this fundamental, mathematical understanding of const, we 
 are just tweaking and hacking and patching in hopes we can come up with 
 something good enough.

I can believe that Walter and crew have done something close to this level of thinking and analysis about the const issue. The problem is that they haven't shown their work. They've presented the conclusion without the intermediate steps required to get to the conclusion. In my 7th grade math class, I recall that not showing my work meant I got 0 credit even if the answer was right. So it comes back to documentation again. It could be a lot better than it is. I'd like to see an expanded/alternate version of 'here a const there a const' that actually covers all aspects of D const, rather than just trying to make fun of C++. http://www.digitalmars.com/d/2.0/const.html --bb
Mar 28 2008
prev sibling next sibling parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Walter Bright wrote:
 I appreciate the time and effort you made to explain your thoughts. I'll 
 try and answer them.

Thank you for your explanation. It must be quite an effort battling all the negativism against it. I'll try to make this a constructive post.
 Benji Smith wrote:
 CONST


[snip]
 I understand your and others' frustration with const, and here's what I 
 think it is based on:
 
 1) We worked hard on what is the right way to do const for a year. This 
 included at least 3 very different implementations of const that were 
 released. The first two turned out to be very wrong and unworkable, and 
 we learned from that how to do it right. 

Ironically, I found the first implementation of const to be the best of the three. There were issues, but the design was for the most part sound. My main complaint was the bad choice of keywords. (My personal theory is that the poor choice of keywords indirectly influenced the design in negative ways. In particular the misconception that const had anything to do with constants.) I will not muddle the issues by arguing keyword names in this post though. I think the current const regime suffers from a greater degree of keyword overloading and redundancy than the original one did. I will try to communicate an idea for what I would believe would make significant simplifications without the loss of any expressive power. (this is mostly from a post I wrote, but never submitted a about two months ago.) I will start with what I call "plain data types", i.e: * all primitive non-reference types (int,float,char,...) * structs and unions containing only plain data types. Plain data types are represented by binary data patterns stored in registers, on the stack, on the heap or just by the compiler during compilation. The data is not interpreted by the compiler as a reference to other data in any way (even though it could, like in the case of an array index), so there is no notion of transitivity here. When it comes to data referred to by a symbol (like a variable name) there are only two cases: variable and constant data. D1.0 handles this quite well with the concept of "storage const". Variables with a const storage can not be changed, but that fact is not reflected in the type of the data. Does the constancy have to be a part of the type? I used to believe so, but have been unable to find a good reason. Binding constancy is a local thing. Example or how it could work: int a; "constant" int b; typeof(a) == int typeof(b) == int typeof(&a) == int* typeof(&b) == invariant(int)* This leads to my first observation: 1. Plain data types don't need the storage constancy to be a part of the type. (I can elaborate on this further if anyone is interested.) My second observation is regarding the so called "manifest constants". Walter stating that there needs to be a way to declare constants that aren't "const" or "invariant" actually reinforces my belief that my first observation is correct. The only reason I have found for the manifest constants are that they don't occupy storage in the object file. I have asked before but never gotten an answer: Can't this be solved automatically by the compiler instead? I will assume that it could, so: 2. Every constant could be a "manifest" constant and just like a template not be instantiated unless it has its address taken. This would, as a side effect, make the entire enum keyword debacle void, as the need for a separate keyword vanishes. Now, what about the concepts of const/invariant? They have nothing to do with the actual data, and only make sense in relation to a reference to such data. Consider: invariant(int)* a; Here, a is actually not a pointer to an invariant int. It is a pointer that assumes the int it points to is "invariant". The difference is subtle but quite important. Likewise: const(int)* b; is not a pointer to a const int. It is a pointer through which the user is disallowed to change the int. That doesn't mean that the int it points to is actually const. the const(...)* and invariant(...)* part of the type declaration should actually be considered a part of the pointer type. Not a part of the target type. So, const and invariant are type meta qualifiers, that carry assumptions about the data. Those assumptions make sense in the context of references, but not in declarations of plain data variables. For example, given: const int x = 5; D 2.010 assigns the type of &x const(int)*. But I would consider that wrong. The type should be invariant(int)*, since x is storage constant. The actual type of x could actually just as well be int (observation 1). Local (storage) constancy doesn't need to be a part of the type. Now, I will not discuss the keywords used for reference constancy, but I think the keyword used to declare constants should be "const". Apart from being how it already almost works in D2, it would have the major advantage of making: const x = 5; mean exactly the same thing in D1 and D2! So, without any loss of power, transitivity or anything else, one can simplify the language and make the constancy of plain data compatible between D2 and D1. That is what I believe at least. -- Oskar
Mar 28 2008
next sibling parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Janice Caron wrote:
 On 28/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:
  1. Plain data types don't need the storage constancy to be a part of the
  type.

But they do, for the following reason. Suppose I implement a custom container. Then I would want MyContainer!(char) to behave differently from MyContainer!(const(char)) The only way I can see of achieving this is if char and const(char) are distinct types.

I called const/invariant "type meta qualifiers". They are not part of the type but carry type meta information. It makes sense that you are able to pass the type meta qualifiers to templates that make use of them. There is an analogue with how templates today by default strip the type meta qualifiers. -- Oskar
Mar 28 2008
parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Oskar Linde wrote:
 Janice Caron wrote:
 On 28/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:
  1. Plain data types don't need the storage constancy to be a part of 
 the
  type.

But they do, for the following reason. Suppose I implement a custom container. Then I would want MyContainer!(char) to behave differently from MyContainer!(const(char)) The only way I can see of achieving this is if char and const(char) are distinct types.

I called const/invariant "type meta qualifiers". They are not part of the type but carry type meta information. It makes sense that you are able to pass the type meta qualifiers to templates that make use of them. There is an analogue with how templates today by default strip the type meta qualifiers.

Some more things to add. Today, say I want to make my own array slice type: struct Slice(T:T) { T[] slice; } Now, I can declare such slices: Slice!(int) a; Slice!(const int) b; const Slice!(int) c; const Slice!(const int) d; You get some quite different beasts that way due to the transitive const. For example, what is the difference between c and d? (Apart from them being distinct types) -- Oskar
Mar 28 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Oskar Linde wrote:
 You get some quite different beasts that way due to the transitive 
 const. For example, what is the difference between c and d? (Apart from 
 them being distinct types)

They do have distinct types, but const(int) is implicitly convertible to int, so the use cases do work out.
Mar 28 2008
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Oskar Linde (oskar.lindeREM OVEgmail.com)'s article
 Walter Bright wrote:
 I appreciate the time and effort you made to explain your thoughts. I'll
 try and answer them.

the negativism against it. I'll try to make this a constructive post.
 Benji Smith wrote:
 CONST


 I understand your and others' frustration with const, and here's what I
 think it is based on:


Well said. Some questions below. ...
 Now, I will not discuss the keywords used for reference constancy, but I
 think the keyword used to declare constants should be "const". Apart
 from being how it already almost works in D2, it would have the major
 advantage of making:
 const x = 5;
 mean exactly the same thing in D1 and D2!
 So, without any loss of power, transitivity or anything else, one can
 simplify the language and make the constancy of plain data compatible
 between D2 and D1.

I think the need for const vs. invariant in D 2.0 is that the compiler isn't smart enough to know when the referenced data should actually never change, and because a bunch of interesting optimizations are available when the data really doesn't ever change, we have a keyword to hint to the compiler that this is true. It's much like "register" in C/C++. That said, I'm still not convinced that it's a good idea to allocate an additonal keyword simply to convey this information to the compiler. I'd still like to believe that there's a better way, and like "register", I expect "invariant" to be rendered completely useless at some point in the future. Sean
Mar 28 2008
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Sean Kelly Wrote:

 == Quote from Oskar Linde (oskar.lindeREM OVEgmail.com)'s article
 Walter Bright wrote:
 I appreciate the time and effort you made to explain your thoughts. I'll
 try and answer them.

the negativism against it. I'll try to make this a constructive post.
 Benji Smith wrote:
 CONST


 I understand your and others' frustration with const, and here's what I
 think it is based on:


Well said. Some questions below. ...
 Now, I will not discuss the keywords used for reference constancy, but I
 think the keyword used to declare constants should be "const". Apart
 from being how it already almost works in D2, it would have the major
 advantage of making:
 const x = 5;
 mean exactly the same thing in D1 and D2!
 So, without any loss of power, transitivity or anything else, one can
 simplify the language and make the constancy of plain data compatible
 between D2 and D1.

I think the need for const vs. invariant in D 2.0 is that the compiler isn't smart enough to know when the referenced data should actually never change, and because a bunch of interesting optimizations are available when the data really doesn't ever change, we have a keyword to hint to the compiler that this is true. It's much like "register" in C/C++. That said, I'm still not convinced that it's a good idea to allocate an additonal keyword simply to convey this information to the compiler. I'd still like to believe that there's a better way, and like "register", I expect "invariant" to be rendered completely useless at some point in the future.

In my dream world implementation of all things const, D would do the following things: readonly (ro, or some variant) would mean a read only view invariant would mean the data never changes, period manifest declares a manifest constant const would have two meanings: 1. Variable declarations - a true constant 2. Function parameters - a promise not to modify the data In both forms of const, optimizations are the compiler's job. A constant *might* be made a manifest constant, but that's not the programmer's concern. The compiler should make it manifest as appropriate (depends on both type and usage of the type) As function inputs, it signifies the programmer's intent. It's up to the compiler to deduce readonly or invariant based on what's getting fed to the function. This vision has led me down the road of trying to figure out implicit const-related casting rules such that the compiler *could* do such optimizations. One day maybe people will share that vision and we can talk about improving the const design instead of defending its current form.
 
 
 Sean

Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 In my dream world implementation of all things const, D would do the following
things:
   readonly (ro, or some variant) would mean a read only view
   invariant would mean the data never changes, period
   manifest declares a manifest constant
   const would have two meanings:
     1. Variable declarations - a true constant
     2. Function parameters - a promise not to modify the data

That's 5 different kinds of constants (as opposed to the current 3). I can hear the protests already <g>.
Mar 28 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 (as opposed to the current 3).

There are currently five :-) (1) mutable (2) invariant (3) const (4) in (5) enum It's not fair to count Jason's "manifest" but not your own "enum"! :-)

Point taken, but Jason didn't mention enum either, and enum's are a way to declare constants. 'in' has always been a solution looking for a problem, I think we can ignore that.
Mar 28 2008
prev sibling parent reply Benji Smith <benji benjismith.net> writes:
Sean Kelly wrote:
 I think the need for const vs. invariant in D 2.0 is that the compiler isn't
 smart enough to know when the referenced data should actually never
 change, and because a bunch of interesting optimizations are available
 when the data really doesn't ever change, we have a keyword to hint to
 the compiler that this is true.

If the compiler can't actually detect mutation of const values, then how will it enforce const correctness? Is the 'const' keyword just a fancy compiler-enforced form of documentation?
 It's much like "register" in C/C++.

I was thinking the same thing myself, which is one of the reasons I dislike the constness being part of the type. In C++ "register" isn't part of the type system. It's just an optimization hint. --benji smith
Mar 28 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Benji Smith (benji benjismith.net)'s article
 Sean Kelly wrote:
 I think the need for const vs. invariant in D 2.0 is that the compiler isn't
 smart enough to know when the referenced data should actually never
 change, and because a bunch of interesting optimizations are available
 when the data really doesn't ever change, we have a keyword to hint to
 the compiler that this is true.

will it enforce const correctness? Is the 'const' keyword just a fancy compiler-enforced form of documentation?

The compiler can locally, but what if it doesn't have access to the entire program source when compiling a module? For example, let's say I create a library function like so: void doSomething( const(char)[] buf, void delegate() dg ) { writefln( buf ); // A dg(); writefln( buf ); // B } If the compiler knows that the data referenced by buf will not change for the entire length of the call to doSomething() then it can cache information about buf in registers, etc. However, doSomething() contains an opaque call to external code, which could in theory modify the contents of buf. Consider: char[] inp = "hello world"; doSomething( inp, () { inp[0] = 'j'; } ); So because there is an opaque call inside doSomething(), the compiler must assume that the contents of buf may change across that call, and therefore may only assume that buf is invariant from the beginning of doSomething() up to the call to dg(), then from the call of dg() to the end of doSomething(). What I don't like about 'invariant' is that while the label is in the correct or at least the easiest place for the compiler, its location means code duplication for the programmer if she wants to have her function work for both constant and non-constant data. This is fine for passing shared data between threads: class MyClass { private string m_s; void setString( string s ) { m_s = s; } void setString( char[] s ) { m_s = s.idup; } } as it avoids the need to perform a copy, or more generally, to acquire a mutex. However, I think the far more common case will be that library programmers will want to create algorithms that work on any kind of string and have the compiler simply optimize the code ideally for each situation: size_t find(T)( in T[] buf, T pat ) { foreach( i, e; buf ) if( e == pat ) return i; return buf.length; } Here, the need to create separate, identical implementations for the same algorithm that vary only by the constancy of buf simply so the compiler can optimize differently for each aspect is horrible. I would much rather have the compiler invisibly generate the different permutations for me and do something fancy with the name mangling to sort out all out invisibly. So: "abc".find( 'b' ); // calls the "invariant(char)[]" permutation char[] buf; buf.find( 'b' ); // calls the "const(char)[]" permutation Of course, this means that the compiler will silently be generating more code but so what? A decent linker could throw out the unused routines anyway. I haven't given this idea much thought, but on the surface it seems like it could do away with the need for 'invariant' almost entirely. Sean
Mar 28 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Janice Caron (caron800 googlemail.com)'s article
 On 28/03/2008, Sean Kelly <sean invisibleduck.org> wrote:
  Here, the need to create separate, identical implementations for the same
  algorithm that vary only by the constancy of buf simply so the compiler can
  optimize differently for each aspect is horrible.

came up with a solution, which I later simplified. It's probably not something that will happen any time soon, but just to let you know, it has been thought about, and a solution proposed.
  I would much rather have
  the compiler invisibly generate the different permutations for me and do
  something fancy with the name mangling to sort out all out invisibly.  So:

  "abc".find( 'b' ); // calls the "invariant(char)[]" permutation
  char[] buf; buf.find( 'b' ); // calls the "const(char)[]" permutation


Nice to know I'm not the only one that feels this way :-) Sean
Mar 28 2008
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Janice Caron (caron800 googlemail.com)'s article
 On 28/03/2008, Janice Caron <caron800 googlemail.com> wrote:
 Yep, that's what we solved. :-)

that case, please ignore my previous post. Your template works just fine. Why don't you like it?

Because to get the compiler optimizations specific to invariant I'd have to create a duplicate that varies only in its acceptance of an "invariant(char)[] buf" rather than an "in char[] buf". Such duplication is pointless if the code is identical in each case. Sean
Mar 28 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Sean Kelly (sean invisibleduck.org)'s article
 == Quote from Benji Smith (benji benjismith.net)'s article
 Sean Kelly wrote:
 I think the need for const vs. invariant in D 2.0 is that the compiler isn't
 smart enough to know when the referenced data should actually never
 change, and because a bunch of interesting optimizations are available
 when the data really doesn't ever change, we have a keyword to hint to
 the compiler that this is true.

will it enforce const correctness? Is the 'const' keyword just a fancy compiler-enforced form of documentation?

program source when compiling a module? For example, let's say I create a library function like so: void doSomething( const(char)[] buf, void delegate() dg ) { writefln( buf ); // A dg(); writefln( buf ); // B } If the compiler knows that the data referenced by buf will not change for the entire length of the call to doSomething() then it can cache information about buf in registers, etc. However, doSomething() contains an opaque call to external code, which could in theory modify the contents of buf. Consider: char[] inp = "hello world"; doSomething( inp, () { inp[0] = 'j'; } ); So because there is an opaque call inside doSomething(), the compiler must assume that the contents of buf may change across that call, and therefore may only assume that buf is invariant from the beginning of doSomething() up to the call to dg(), then from the call of dg() to the end of doSomething(). What I don't like about 'invariant' is that while the label is in the correct or at least the easiest place for the compiler, its location means code duplication for the programmer if she wants to have her function work for both constant and non-constant data. This is fine for passing shared data between threads: class MyClass { private string m_s; void setString( string s ) { m_s = s; } void setString( char[] s ) { m_s = s.idup; } } as it avoids the need to perform a copy, or more generally, to acquire a mutex. However, I think the far more common case will be that library programmers will want to create algorithms that work on any kind of string and have the compiler simply optimize the code ideally for each situation: size_t find(T)( in T[] buf, T pat ) { foreach( i, e; buf ) if( e == pat ) return i; return buf.length; } Here, the need to create separate, identical implementations for the same algorithm that vary only by the constancy of buf simply so the compiler can optimize differently for each aspect is horrible. I would much rather have the compiler invisibly generate the different permutations for me and do something fancy with the name mangling to sort out all out invisibly. So: "abc".find( 'b' ); // calls the "invariant(char)[]" permutation char[] buf; buf.find( 'b' ); // calls the "const(char)[]" permutation Of course, this means that the compiler will silently be generating more code but so what? A decent linker could throw out the unused routines anyway. I haven't given this idea much thought, but on the surface it seems like it could do away with the need for 'invariant' almost entirely. Sean

No one liked this idea, huh? :-) One thought for reducing the number of permutations was to only permute on "in" parameters. Explicitly specified "const" or "invariant" parameters are left as-is. Another possible reduction would be to only do this for template functions, though this would be somewhat of an odd special case. Sean
Apr 01 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Sean Kelly" wrote
 No one liked this idea, huh? :-)  One thought for reducing the number of
 permutations was to only permute on "in" parameters.  Explicitly specified
 "const" or "invariant" parameters are left as-is.  Another possible 
 reduction
 would be to only do this for template functions, though this would be
 somewhat of an odd special case.

This would help I think: http://d.puremagic.com/issues/show_bug.cgi?id=1961 -Steve
Apr 01 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Benji Smith wrote:
 I was thinking the same thing myself, which is one of the reasons I 
 dislike the constness being part of the type. In C++ "register" isn't 
 part of the type system. It's just an optimization hint.

It can't be just an optimization hint. For example, if I pass const(T*) to a function foo(), that means I want to guarantee that foo() does not change it. Having the compiler accept that foo() changes it, and so disable some optimization somewhere, does me no good at all.
Mar 28 2008
parent reply Benji Smith <benji benjismith.net> writes:
Walter Bright wrote:
 Benji Smith wrote:
 I was thinking the same thing myself, which is one of the reasons I 
 dislike the constness being part of the type. In C++ "register" isn't 
 part of the type system. It's just an optimization hint.

It can't be just an optimization hint. For example, if I pass const(T*) to a function foo(), that means I want to guarantee that foo() does not change it. Having the compiler accept that foo() changes it, and so disable some optimization somewhere, does me no good at all.

I'm still not convinced that whether or not a function modifies its argument values has anything to do with the type system. At the very least, it only applies to the function's type, not the types of the arguments. The automatic casting of arguments to const, for no purpose other than to satisfy the type system, feels wrong to me. With one hand, you're creating a restriction in the type system, and with the other hand, you're creating a loophole in the type system that only applies to this specific case. I can feel occam's razor prickling at my brain, and it doesn't sit well with me. Just because a function promises not to modify its argument doesn't mean the function can only accept an immutable value. It should accept any value at all, without discriminating based on mutability. In fact, the mutability of the arguments only matters *within* the function (and further down the call stack). To me, that sounds more like a storage class (or some other type of declaration modifier). But even putting aside the type-system for a moment, I still think that much of the emphasis of const-correctness is misdirected. Asking a method or function to document which arguments it *DOESN'T* modify is a lot like asking the police to keep a detailed record of all law-abiding citizens, as a roundabout way of tracking down criminals. Or calling the doctor everytime you're not sick, so that he can set an appointment for you whenever you don't call. What about a special syntax to denote all functions that don't throw exceptions? Wouldn't it make more sense to annotate *MUTABILITY* of function arguments? Otherwise, you end up with a bunch of 'const' clutter all over the place: int str_search(const(char[]) needle, const(char[]) haystack, const(char)* start, const(char)* end); Egads. It's a nightmare. Isn't this code better, in nearly every way? int str_search(char[] haystack, char[] needle, char* start, char* end); At a quick glance, I can see that this function is not going to modify any of its arguments (since none of them are marked as 'mutable'), so I can pass any values I want. The function doesn't care whether it *receives* mutable or immutable values, since it's not going to mutate them one way or the other. On the other hand, I might have a function declared like this: void str_replace(mutable char[] haystack, char[] needle, char[] replacement, char* start, char* end); In this case, there's only one argument that might be modified by the function. Any caller of this function must ensure that the 'haystack' variable provides a mutable view. The other argument values remain unrestricted, so the caller of this function only has to fuss about with one restriction. It's easier on the brain that way. What if, as a library author, I forgot to mark the haystack variable as mutable? Or if my code accidentally modifies the contents of one of the other variables? As soon as I touch the data in that array, the compiler should throw a huge tantrum. Shazzam! Const-correct! And unlike the ever-so-common casting away of "const-ness", casting away mutability should be completely impossible. Under the current regime, the prototype of this method is quite a bit more bulky: void str_replace(char[] haystack, const(char)[] needle, const(char)[] replacement, const(char)* start, const(char)* end); Resenting all that extra typing, I'm likely to get lazy and leave off a few of those const modifiers. Either out of my trademark forgetfulness, or just because I'm a spiteful person: void str_replace(char[] haystack, char[] needle, char[] replacement, char* start, char* end); Now the compiler is hamstrung. It can't enforce anything. I can change the values of any argument without a single warning message. So much for const-correctness. There's nothing special about a value not changing (at least, not for function arguments), so programmers should't be burdened with annotating the mundane case. Mutability of function arguments is much more interesting. Labeling function arguments as mutable would, in my opinion, provide a *stronger* const regime, while simultaneously producing less pointless code clutter. As for 'invariant' data (and its relocation to read-only memory or whatever), my opinion is: let the compiler do whatever optimizations it wants. I'd rather declare that kind of data as "const", and if the compiler can figure out that a pointer to the data is never taken, then it can burn the value into silicon as far as I care. (Incidentally, when I started this thread, I meant no disrespect toward Walter or Andrei or anyone else for the massive amount of excellent work that they've done. I just wanted to register a few opinions about choices that make the language somewhat less appealing to me.) Thanks, everybody, for listening. I've read all the replies so far, and I have a few other things I'd like to say about strings and arrays and whatnot, but this post reflects the entirety of my current thinking about const. --benji smith
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Benji Smith wrote:
 I'm still not convinced that whether or not a function modifies its 
 argument values has anything to do with the type system.

It has to travel along with the types in a manner that is indistinguishable from being part of the type system, so it might as well be. We did initially try to keep them separate; that didn't last long.
 At the very 
 least, it only applies to the function's type, not the types of the 
 arguments.

That's correct. The argument types must be implicitly convertible to the corresponding parameter types.
 The automatic casting of arguments to const, for no purpose other than 
 to satisfy the type system, feels wrong to me. With one hand, you're 
 creating a restriction in the type system, and with the other hand, 
 you're creating a loophole in the type system that only applies to this 
 specific case. I can feel occam's razor prickling at my brain, and it 
 doesn't sit well with me.

By a loophole I infer there's something unsound going on. But I don't see what it is you're referring to.
 Just because a function promises not to modify its argument doesn't mean 
 the function can only accept an immutable value. It should accept any 
 value at all, without discriminating based on mutability.

It does, that's the point of the const qualifier. All types are implicitly convertible to const.
 In fact, the 
 mutability of the arguments only matters *within* the function (and 
 further down the call stack). To me, that sounds more like a storage 
 class (or some other type of declaration modifier).
 
 But even putting aside the type-system for a moment, I still think that 
 much of the emphasis of const-correctness is misdirected.
 
 Asking a method or function to document which arguments it *DOESN'T* 
 modify is a lot like asking the police to keep a detailed record of all 
 law-abiding citizens, as a roundabout way of tracking down criminals. Or 
 calling the doctor everytime you're not sick, so that he can set an 
 appointment for you whenever you don't call.

It's a reasonable position to take that parameters are const by default, and must be explicitly marked as mutable in order to change them. The horrible problem with that, however, is that it will work in the reverse way that other declarations work. It's inconsistent in a very perverse way.
 What about a special syntax 
 to denote all functions that don't throw exceptions?

There is a proposed one: nothrow.
 
 Wouldn't it make more sense to annotate *MUTABILITY* of function arguments?
 
 Otherwise, you end up with a bunch of 'const' clutter all over the place:
 
    int str_search(const(char[]) needle, const(char[]) haystack,
       const(char)* start, const(char)* end);
 
 Egads. It's a nightmare.
 
 Isn't this code better, in nearly every way?
 
    int str_search(char[] haystack, char[] needle, char* start,
       char* end);
 
 At a quick glance, I can see that this function is not going to modify 
 any of its arguments (since none of them are marked as 'mutable'), so I 
 can pass any values I want. The function doesn't care whether it 
 *receives* mutable or immutable values, since it's not going to mutate 
 them one way or the other.
 
 On the other hand, I might have a function declared like this:
 
    void str_replace(mutable char[] haystack, char[] needle,
       char[] replacement, char* start, char* end);
 
 In this case, there's only one argument that might be modified by the 
 function. Any caller of this function must ensure that the 'haystack' 
 variable provides a mutable view. The other argument values remain 
 unrestricted, so the caller of this function only has to fuss about with 
 one restriction.
 
 It's easier on the brain that way.
 
 What if, as a library author, I forgot to mark the haystack variable as 
 mutable? Or if my code accidentally modifies the contents of one of the 
 other variables?
 
 As soon as I touch the data in that array, the compiler should throw a 
 huge tantrum.
 
 Shazzam! Const-correct!
 
 And unlike the ever-so-common casting away of "const-ness", casting away 
 mutability should be completely impossible.
 
 Under the current regime, the prototype of this method is quite a bit 
 more bulky:
 
    void str_replace(char[] haystack, const(char)[] needle,
       const(char)[] replacement, const(char)* start, const(char)* end);
 
 Resenting all that extra typing, I'm likely to get lazy and leave off a 
 few of those const modifiers. Either out of my trademark forgetfulness, 
 or just because I'm a spiteful person:
 
    void str_replace(char[] haystack, char[] needle, char[] replacement,
       char* start, char* end);
 
 Now the compiler is hamstrung. It can't enforce anything. I can change 
 the values of any argument without a single warning message.

You will get an error if you try passing a string to that function.
 
 So much for const-correctness.

I agree with some of the awfulness of the syntax. That's where 'in' comes in: void str_replace(in char[] haystack, in char[] needle, in char[] replacement, in char* start, in char* end); Not perfect, but not so awful. You should also be using string's instead of char[], as they are invariant and you don't need to annotate string parameters.
 There's nothing special about a value not changing (at least, not for 
 function arguments), so programmers should't be burdened with annotating 
 the mundane case. Mutability of function arguments is much more 
 interesting.
 
 Labeling function arguments as mutable would, in my opinion, provide a 
 *stronger* const regime, while simultaneously producing less pointless 
 code clutter.

As this has come up before, I added it to const(FAQ): http://www.digitalmars.com/d/2.0/const-faq.html#const-parameters
 As for 'invariant' data (and its relocation to read-only memory or 
 whatever), my opinion is: let the compiler do whatever optimizations it 
 wants. I'd rather declare that kind of data as "const", and if the 
 compiler can figure out that a pointer to the data is never taken, then 
 it can burn the value into silicon as far as I care.

I don't want the compiler to figure out that I never took a mutable pointer to it, I want the compiler to *prevent* me from taking a pointer to it by mistake.
 (Incidentally, when I started this thread, I meant no disrespect toward 
 Walter or Andrei or anyone else for the massive amount of excellent work 
 that they've done. I just wanted to register a few opinions about 
 choices that make the language somewhat less appealing to me.)

Thank you, and I never took your comments any other way. In fact, I'm glad you took the time to put them to paper.
 Thanks, everybody, for listening. I've read all the replies so far, and 
 I have a few other things I'd like to say about strings and arrays and 
 whatnot, but this post reflects the entirety of my current thinking 
 about const.

I'll look forward to it.
Mar 28 2008
parent reply Benji Smith <benji benjismith.net> writes:
Walter Bright wrote:
 Benji Smith wrote:
 There's nothing special about a value not changing (at least, not for 
 function arguments), so programmers should't be burdened with 
 annotating the mundane case. Mutability of function arguments is much 
 more interesting.

 Labeling function arguments as mutable would, in my opinion, provide a 
 *stronger* const regime, while simultaneously producing less pointless 
 code clutter.

As this has come up before, I added it to const(FAQ): http://www.digitalmars.com/d/2.0/const-faq.html#const-parameters

Cool. Thanks! In the FAQ, you said "This kind of inconsistency leads to all sorts of mistakes." I'd like to point out that we don't really know if it causes mistakes, because no one has ever tried it. At least they'd be the kind of mistakes that the compiler could catch. "Error: can't modify the value of a non-mutable argument, on line 235" With the current implementation, if a programmer forgets to annotate an argument as const, the compiler can't correct the error. The FAQ also says "It would be a huge break from past D practice, and practice in C, C++, Jave, C#, etc." But isn't the same thing true of transitive const? You yourself said that no other language has ever implemented transitive const. So it's a huge break from the past for all of us. It takes some brain-readjustment to understand the mechanics of it, let alone the implications for designing an API. (BTW, none of my comments so far have been about const transitivity, because I don't understand it well enough to form an opinion.) ...hmmmmmm... browsing through the rest of the FAQ... I'm particularly interested in your "logical const" example, because it demonstrates a memoization idiom that I use all over the place in my everyday coding. For example, I do a lot of work with vector-space representations of data, and I have a bunch of classes for modeling vector spaces and vectors within those spaces. Each vector usually represents some sort of document, and the magnitude in each dimension usually represents the term frequency (or, more generically, a weight for whatever feature is modeled by the given dimension). It's not uncommon for an individual vector to have hundreds or thousands of dimensions. In one of my projects, the full vector space had more than half a million distinct dimensions, and the biggest vectors each projected into ten or fifteen thousand of those dimensions. With such a model, you can calculate the "information weight" of a vector by taking its magnitude. Or you can calculate similarities between two documents by taking the cosine of their vectors. Vector cosine is calculated by dividing the vectors' dot products by the product of the vector magnitudes. And, since I often need to calculate thousands of these vector cosines (to find a pair of documents with high similarity), each vector object lazily calculates (and then memoizes) its magnitude. I can't remember the exact results, but when I implemented magnitude memoization, my algorithms sped up by at least an order of magnitude. On the one hand, the vector itself (once constructed) is const, becuase I never add, remove, or alter the value of any dimension. But if a vector's magnitude is never requested (either directly or through a cosine calculation), then the magnitude is never calculated. I'd be sunk without the availability of that kind of functionality. I use it all over the place. (Especially for calculating object hash codes (the majority of my code is in Java and C#)). I suppose in D, I'd have to avoid declaring vectors as const. Which would be a shame, because the basic data in the structure is never modified after construction. The only thing that *ever* changes is those values that are lazily evaluated and then memoized. Hope that info is helpful. (Or at least mildly entertaining!) --benji smith
Mar 28 2008
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Benji Smith wrote:
 I'd like to point out that we don't really know if it causes mistakes, 
 because no one has ever tried it.

True, but we do have experience where A means !A are juxtaposed with A means A, and it's pretty much always bad.
 At least they'd be the kind of mistakes that the compiler could catch.

It hurts my brain to constantly have to think twice about what a particular declaration means, since it will shift depending on the context.
 "Error: can't modify the value of a non-mutable argument, on line 235"
 
 With the current implementation, if a programmer forgets to annotate an 
 argument as const, the compiler can't correct the error.

It can issue an error if the argument is const, but the parameter is mutable.
 The FAQ also says "It would be a huge break from past D practice, and 
 practice in C, C++, Jave, C#, etc."
 
 But isn't the same thing true of transitive const? You yourself said 
 that no other language has ever implemented transitive const. So it's a 
 huge break from the past for all of us. It takes some brain-readjustment 
 to understand the mechanics of it, let alone the implications for 
 designing an API.

Let's look at another case. Gcc has inline assembler, and its arguments are exactly backwards from Digital Mars/Microsoft/Intel inline assembler. This screwing with my brain makes it extremely difficult for me to use it. It's not just a shift in meaning in a new direction, it's a *reversal* of meaning. It's like (well, not as bad as) exchanging the meaning of the * and + operators.
 (BTW, none of my comments so far have been about const transitivity, 
 because I don't understand it well enough to form an opinion.)
 
 ...hmmmmmm... browsing through the rest of the FAQ...
 
 I'm particularly interested in your "logical const" example, because it 
 demonstrates a memoization idiom that I use all over the place in my 
 everyday coding.
 
 For example, I do a lot of work with vector-space representations of 
 data, and I have a bunch of classes for modeling vector spaces and 
 vectors within those spaces.
 
 Each vector usually represents some sort of document, and the magnitude 
 in each dimension usually represents the term frequency (or, more 
 generically, a weight for whatever feature is modeled by the given 
 dimension). It's not uncommon for an individual vector to have hundreds 
 or thousands of dimensions.
 
 In one of my projects, the full vector space had more than half a 
 million distinct dimensions, and the biggest vectors each projected into 
 ten or fifteen thousand of those dimensions.
 
 With such a model, you can calculate the "information weight" of a 
 vector by taking its magnitude. Or you can calculate similarities 
 between two documents by taking the cosine of their vectors.
 
 Vector cosine is calculated by dividing the vectors' dot products by the 
  product of the vector magnitudes. And, since I often need to calculate 
 thousands of these vector cosines (to find a pair of documents with high 
 similarity), each vector object lazily calculates (and then memoizes) 
 its magnitude.
 
 I can't remember the exact results, but when I implemented magnitude 
 memoization, my algorithms sped up by at least an order of magnitude.
 
 On the one hand, the vector itself (once constructed) is const, becuase 
 I never add, remove, or alter the value of any dimension. But if a 
 vector's magnitude is never requested (either directly or through a 
 cosine calculation), then the magnitude is never calculated.
 
 I'd be sunk without the availability of that kind of functionality. I 
 use it all over the place. (Especially for calculating object hash codes 
 (the majority of my code is in Java and C#)).
 
 I suppose in D, I'd have to avoid declaring vectors as const. Which 
 would be a shame, because the basic data in the structure is never 
 modified after construction. The only thing that *ever* changes is those 
 values that are lazily evaluated and then memoized.

While you cannot use const for such a class, I don't see how not using const hurts it.
Mar 29 2008
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2008-03-29 01:07:44 -0400, Benji Smith <benji benjismith.net> said:

 I suppose in D, I'd have to avoid declaring vectors as const. Which 
 would be a shame, because the basic data in the structure is never 
 modified after construction. The only thing that *ever* changes is 
 those values that are lazily evaluated and then memoized.

I think the idea here is that your vector class shouldn't be const, but your vector data inside the vector class could be const or invariant. Something like this: class Vector { invariant(VectorData) data; CalculationCache cache; /* accessors */ } If you create a constant Vector then you can't change the cached values, but that's just asserting the reality: your Vector object isn't constant if its cache isn't and the compiler cannot make optimizations by assuming constancy of the Vector object. In my example above, the vector's data is invariant though, and calculating things using this data may benefit from automatic optimizations for invariant data (like pararalelizing, when the compiler supports that). So, despite sharing the same keyword, D const isn't a logical const like in C++, it's an optimization-enabling const for the compiler. This means that by making some of your member functions const, you're commiting to a particular implementation of your class or struct where you guarenty you're not changing any bit in it, so you should probably not add const everywhere it seems "logical", like in C++. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Mar 30 2008
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Janice Caron (caron800 googlemail.com)'s article
 On 28/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:
  1. Plain data types don't need the storage constancy to be a part of the
  type.

container. Then I would want MyContainer!(char) to behave differently from MyContainer!(const(char)) The only way I can see of achieving this is if char and const(char) are distinct types.

Or if there are two distinct container types. ie. MyCotainerView!(char) and MyContainer!(char). This doesn't require language support to achieve. Sean
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 Right. But that would mean that MyContainer could never behave like a
 built-in array. The ability to mimic built-in arrays with custom
 containers is highly desirable, as I'm sure you will agree. So, if I
 want MyContainer!(char) to mimic char[], and MyContainer!(const(char))
 to mimic const(char)[], then I really need to make that distinction.

Yes, that was another issue we wanted as an axiom - we could wrap any type with a struct and have it work like the underlying type. This axiom drove a lot of decisions about how things work.
Mar 28 2008
parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright wrote:

 Janice Caron wrote:
 Right. But that would mean that MyContainer could never behave like a
 built-in array. The ability to mimic built-in arrays with custom
 containers is highly desirable, as I'm sure you will agree. So, if I
 want MyContainer!(char) to mimic char[], and MyContainer!(const(char))
 to mimic const(char)[], then I really need to make that distinction.

Yes, that was another issue we wanted as an axiom - we could wrap any type with a struct and have it work like the underlying type. This axiom drove a lot of decisions about how things work.

A page online about how wrapping types in structs drove the design would be nice to see.
Mar 28 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 A page online about how wrapping types in structs drove the design would be
 nice to see.

Good idea.
Mar 28 2008
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 The only way I can see of achieving this is if char and const(char)
 are distinct types.

We went around on that for a while. It turns out that for generic code to work, T and const(T) had to be distinct types, even if T was a basic type like char or int.
Mar 28 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Oskar Linde wrote:
 Does the constancy have to be a part of the type?

Yes. Because generic code needs to be able to deconstruct a type and reconstitute it. That means the const has to travel with the components of the type.
 1. Plain data types don't need the storage constancy to be a part of the 
 type.

Right, and that works fine until you try to do generic type manipulation. For example, if you use a template to convert a T* into a T[], you first strip the * off of T*, then add the []. If T was const, then your pointer to const correctly produces an array of const. But if const cannot be applied to a plain data type, then the const'ness will be lost.
 I have asked before but never gotten an answer: Can't this be 
 solved automatically by the compiler instead?

Couldn't find a way that worked.
 Now, what about the concepts of const/invariant? They have nothing to do 
 with the actual data, and only make sense in relation to a reference to 
 such data. Consider:
 
 invariant(int)* a;
 
 Here, a is actually not a pointer to an invariant int. It is a pointer
 that assumes the int it points to is "invariant". The difference is
 subtle but quite important. Likewise:
 
 const(int)* b;
 
 is not a pointer to a const int. It is a pointer through which the user 
 is disallowed to change the int. That doesn't mean that the int it
 points to is actually const.
 
 the const(...)* and invariant(...)* part of the type declaration should 
 actually be considered a part of the pointer type. Not a part of the 
 target type.
 
 So, const and invariant are type meta qualifiers, that carry assumptions 
 about the data. Those assumptions make sense in the context of 
 references, but not in declarations of plain data variables. For 
 example, given:
 
 const int x = 5;
 
 D 2.010 assigns the type of &x const(int)*. But I would consider that 
 wrong. The type should be invariant(int)*, since x is storage constant. 
 The actual type of x could actually just as well be int (observation 1). 
 Local (storage) constancy doesn't need to be a part of the type.

You're right, but again, the problem comes up when you're writing templates that deconstruct and construct types. Taking these semantic shortcuts in the compiler cause havoc with templates. That's why we finally gave up on such and went to a consistent, pedantic approach.
 So, without any loss of power, transitivity or anything else, one can 
 simplify the language and make the constancy of plain data compatible 
 between D2 and D1.

We tried, it almost works but there are enough corner cases to make it just not work. Const is not the way it is now in D for lack of trying to make all these cases work - and trying to make them work was what led to the previous two (failed) const regimes. We spent hundreds of hours working through the issues.
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 That's true, but there's a new idea on the block now. A few posts up,
 I suggested that a declaration like
 
     const int x = 5;
 
 should be interpretted by the compiler as if the statement had been
 
     invariant int x = 5;
 
 (Actually, I used the nonclamenture in/const, instead of
 const/invariant, but the meaning doesn't change with the words).
 
 Essentially, I propose the rule that if any variable is declared to be
 a fully const POD type, then it should be magically retyped to instead
 become fully invariant. Thus, typeof(x) would be invariant(int),
 typeof(&x) would be invariant(int)*, and so on. Hopefully, you can see
 that deconstructing and reconstructing would now still work perfectly.

Yeah, but I can see the bug report now: "dammit, I typed it as const, why is it coming out as invariant?"
Mar 29 2008
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Scott S. McCoy Wrote:

I see all your messages double, or I don't see their text at all... I think you
may be using HTML, and that may produce problems (I am using the web interface
on www.digitalmars.com/webnews/newsgroups.php ).

Bye,
bearophile
Mar 30 2008
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Janice Caron wrote:
 
 Perhaps, but I don't think you've understood that it is /impossible/
 to declare a const variable that isn't, in fact, invariant. Consider:
 
     const int x = 5;
 
 x may be typed const(int), but it is, in fact, really, really,
 invariant. Because not only can you not change it, but no one else can
 either. 

It's impossible? How about: const int x = someFuncThatReturnsConst(); ? Your statement is only true if the said variable is static AND has an initializer. (also, to be more accurate, the type in the example should be changed to something other than a basic type like int) -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 27 2008
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Janice Caron wrote:
 On 27/04/2008, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:
  It's impossible? How about:
   const int x = someFuncThatReturnsConst();

x is still immutable.

Well... in this case yes, but only because it is a basic type. Your assertion still does not hold: "it is /impossible/ to declare a const variable that isn't, in fact, invariant". Like I said just before, the example should have a type other than a basic type: const int* x = someFuncThatReturnsConst(); x is const, not invariant. (altough it does happen that the *head-value* of x is indeed conceptually invariant, because it was copied and is unique) -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 27 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
2008/4/27 Bruno Medeiros <brunodomedeiros+spam com.gmail>:
 x is still immutable.

Well... in this case yes, but only because it is a basic type. Your assertion still does not hold: "it is /impossible/ to declare a const variable that isn't, in fact, invariant".

Again, we're on the same page here. I wasn't precise enough. That rule doesn't hold for all types (as your counterexample shows), it only holds for types which contain no pointers to mutable data. So I should have said "it is impossible to declare a const variable of a type which contains no pointers to mutable data, that isn't itself immutable". (But I know more now than I knew then, and hindsight is easy! :-))
Apr 27 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:
  1. Plain data types don't need the storage constancy to be a part of the
  type.

But they do, for the following reason. Suppose I implement a custom container. Then I would want MyContainer!(char) to behave differently from MyContainer!(const(char)) The only way I can see of achieving this is if char and const(char) are distinct types.
Mar 28 2008
prev sibling next sibling parent Oliver Dathe <o.dathe gmx.de> writes:
Let me first state that I totally agree! As well I'm pretty sure 
transitivity is the exact right way to go.

I think the problem, that people encounter is just the following: 
Usually data is data in process. Therefore it is mutable by nature - 
just no constant. D2 gives the opportunity to declare immutability at 
declarations. Thus it should not be applied to 'data in process' if we 
generally want to avoid unsound operations. This already leaves a large 
/hole/ where people just want to a.) assert, that something they apply 
to their mutable data leaves them invariant but also b.) use a mutable 
result afterwards. Adopting mutable input data by const storage class 
also yields the latter as output. So we've forgotten to remove the lock 
somewhere. You may have to get rid of it by unsound operations.

Currently my suggestion would be some sort of parameter contracts 
[1][2][3] plus (where needed) something that applies the 'const level' 
of a passed parameter to the functions's returntype [4]. I think it 
would not weaken the pro const points 1.-4. but could also avoid 
unnecessary unsound operations that may comprise point 4.

[1][2][3]
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=68285
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=68248
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmar
.D&article_id=68137 

[4] http://s3.amazonaws.com/dconf2007/WalterAndrei.pdf p.38/39

Apart from that: A const property for variables could be a usefull 
thing. e.g. myvar.const would yield a transitive const reference to 
itself - just a shorthand for (cast(const(typeof(myvar)))myvar).
Mar 28 2008
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
So, while we're having (...another...) const rethink, here's my list
of "ideals".

(1) Rename everything. Like many other people, I've always thought the
existing names weren't quite right.

    BEFORE -> AFTER
    const -> in
    invariant -> const
    enum -> const

This will mean we lose the distinction between the current usage of
"const" and "in". Big deal! Who understands the difference anyway?

(2) Manifest constants just work. If something is declared /fully/
const, then you cannot take the address of it.

    const PI = 3.14;
    auto p = &PI; /*ERROR*/

If you want a constant you can take the address of, declare it as "in". e.g.

    in E = 2.72;
    auto p = &E; /*OK*/

(3) Rebindable references to const classes.

    in(T)& c;

...which of course shall be a syntax error if T is not a class. (Same
as Andrei's proposed Rebindable!(const(T))).

(4) Better syntax for const member functions.

    in(this) T f()



Well, that's my list. Probably others will have a different list. But
these are what I see as the things that people are most unhappy about,
and fixing these would buy us a /huge/ amount of goodwill.

At least, in my opinion. But I'm positive that others will chime with
additional opinions.
Mar 28 2008
parent reply sambeau <no-spam-for-sambeau mac.com> writes:
Janice Caron Wrote:

 So, while we're having (...another...) const rethink, here's my list
 of "ideals".
 
 (1) Rename everything. Like many other people, I've always thought the
 existing names weren't quite right.
 
     BEFORE -> AFTER
     const -> in
     invariant -> const
     enum -> const

I like everything apart from "in". "in" to me is for arrays and sets. "inv" would be fine though. "at" might be better than as it reminds you that it is an address. I have floated "let" in the past too.
Mar 28 2008
parent reply Denton Cockburn <diboss hotmail.com> writes:
On Fri, 28 Mar 2008 17:10:18 +0000, Janice Caron wrote:

 My rationale is that in is already used in this context, but currently
 only for function parameters. That is, currently
 
     int f(const T x);
     int f(in T x);
 
 are identical. (Or at least, if they're not identical, I don't
 understand the difference). 

I've been trying to figure out the difference for a while now. I started 2 threads on D newsgroups...neither of which provided a reasonable response. I still would like to see a good explanation of why we have 2 keywords that do the exact same thing (esp. when one has no other purpose - in).
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Denton Cockburn wrote:
 I've been trying to figure out the difference for a while now.
 I started 2 threads on D newsgroups...neither of which provided a
 reasonable response.  I still would like to see a good explanation of why
 we have 2 keywords that do the exact same thing (esp. when one has no
 other purpose - in).

It's a good question. The only value 'in' has is it's shorter.
Mar 28 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Denton Cockburn wrote:
 I've been trying to figure out the difference for a while now.
 I started 2 threads on D newsgroups...neither of which provided a
 reasonable response.  I still would like to see a good explanation of why
 we have 2 keywords that do the exact same thing (esp. when one has no
 other purpose - in).


And it compiles with D 1.0! For better or worse, "in" is currently the salvation of projects that aim to build without changes in D 1.0 and 2.0. Sean
Mar 28 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright wrote:

 Denton Cockburn wrote:
 I've been trying to figure out the difference for a while now.
 I started 2 threads on D newsgroups...neither of which provided a
 reasonable response.  I still would like to see a good explanation of why
 we have 2 keywords that do the exact same thing (esp. when one has no
 other purpose - in).

It's a good question. The only value 'in' has is it's shorter.

I thought in was "const scope". I interpret that to mean that in is stronger than const. It means that the data is not guaranteed to be excessible beyond the function call. I guess with a garbage collected system that makes less sense. Certainly invariant scope makes more sense to me (guarantee invariance only over the duration of the function call)
Mar 28 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 Walter Bright wrote:
 It's a good question. The only value 'in' has is it's shorter.

I thought in was "const scope". I interpret that to mean that in is stronger than const. It means that the data is not guaranteed to be excessible beyond the function call. I guess with a garbage collected system that makes less sense. Certainly invariant scope makes more sense to me (guarantee invariance only over the duration of the function call)

That too, but the semantics of it aren't implemented yet and I'm not sure that's the right thing to do.
Mar 28 2008
prev sibling parent Roberto Mariottini <rmariottini mail.com> writes:
Walter Bright wrote:
 Denton Cockburn wrote:
 I've been trying to figure out the difference for a while now.
 I started 2 threads on D newsgroups...neither of which provided a
 reasonable response.  I still would like to see a good explanation of why
 we have 2 keywords that do the exact same thing (esp. when one has no
 other purpose - in).

It's a good question. The only value 'in' has is it's shorter.

Well, so let's deprecate 'const' and use 'in' instead (this time I'm serious!). Ciao -- Roberto Mariottini, http://www.mariottini.net/roberto/ SuperbCalc, a free tape calculator: http://www.mariottini.net/roberto/superbcalc/
Mar 31 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, sambeau <no-spam-for-sambeau mac.com> wrote:
 I like everything apart from "in". "in" to me is for arrays and sets.

My rationale is that in is already used in this context, but currently only for function parameters. That is, currently int f(const T x); int f(in T x); are identical. (Or at least, if they're not identical, I don't understand the difference). If we're going to introduce a new keyword, then "readonly" would certainly be the most popular choice, judging by past posts on this newsgroup. But "in" would be good if either (a) we wanted to keep the keyword count down, or (b) we felt that "readonly" was too much typing.
  "inv" would be fine though. "at" might be better than as it reminds you that
it is an address.  I have floated "let" in the past too.

Neither of those suggests constancy to me, and I don't think I'd like to see a function declaration like void f(let(char)[] x) I mean, I'd take one look at that and say: "Huh?". But still, it's good to hear opinions. The more the merrier.
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:
 I called const/invariant "type meta qualifiers". They are not part of
  the type but carry type meta information. It makes sense that you are
  able to pass the type meta qualifiers to templates that make use of
  them. There is an analogue with how templates today by default strip the
  type meta qualifiers.

I think that your "orthogonal const proposal" is a good one, but I also think we'd need to express it in different language, or it won't be understood. What you call "type meta qualifiers", Walter calls "part of the type". We all gotta speak the same language. :-) So here's how I think it should work. Note that this is very similar to your proposal, but I'm using different words for things. I'm also using the convention:
     BEFORE -> AFTER
     const -> in
     invariant -> const
     enum -> const

OK, here goes - Janice's rewrite of Oskar's orthoganal const proposal. Tell me if you wildly disagree. const int a; writefln(typeof(a).stringof); // const(int) const(int) b; writefln(typeof(b).stringof); // const(int) in int c; writefln(typeof(c).stringof); // const(int) in(int) d; writefln(typeof(d).stringof); // const(int) ...but... in(int)[] e; writefln(typeof(e).stringof); // in(int)[] Basically, the trick is, a little bit of compiler magic happens, whereby if a declaration declares a POD data type to be /fully/ "in", then the type is magically changed to "const". The second bit of compiler magic is that if a declaration declares something to be /fully/ "const", then the object is deemed to be a manifest constant. Thus: struct S { int x; const n = 10; } writefln(S.sizeof); // 4 ...but... struct T { int x; in n = 10; } writefln(S.sizeof); // 8 Those little compiler reinterpretations of things declared fully const or fully in, I believe, achieve the same thing as your orthogonal const proposal, but they do so without giving the const system a complete overhaul. What do you think?
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Sean Kelly <sean invisibleduck.org> wrote:
  > The only way I can see of achieving this is if char and const(char)
  > are distinct types.

 Or if there are two distinct container types.  ie.

  MyCotainerView!(char) and MyContainer!(char).

Right. But that would mean that MyContainer could never behave like a built-in array. The ability to mimic built-in arrays with custom containers is highly desirable, as I'm sure you will agree. So, if I want MyContainer!(char) to mimic char[], and MyContainer!(const(char)) to mimic const(char)[], then I really need to make that distinction.
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
  > const int x = 5;
  >
  > D 2.010 assigns the type of &x const(int)*. But I would consider that
  > wrong. The type should be invariant(int)*,

 You're right, but again, the problem comes up when you're writing
  templates that deconstruct and construct types. Taking these semantic
  shortcuts in the compiler cause havoc with templates. That's why we
  finally gave up on such and went to a consistent, pedantic approach.

That's true, but there's a new idea on the block now. A few posts up, I suggested that a declaration like const int x = 5; should be interpretted by the compiler as if the statement had been invariant int x = 5; (Actually, I used the nonclamenture in/const, instead of const/invariant, but the meaning doesn't change with the words). Essentially, I propose the rule that if any variable is declared to be a fully const POD type, then it should be magically retyped to instead become fully invariant. Thus, typeof(x) would be invariant(int), typeof(&x) would be invariant(int)*, and so on. Hopefully, you can see that deconstructing and reconstructing would now still work perfectly.
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 (as opposed to the current 3).

There are currently five :-) (1) mutable (2) invariant (3) const (4) in (5) enum It's not fair to count Jason's "manifest" but not your own "enum"! :-)
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Sean Kelly <sean invisibleduck.org> wrote:
  Here, the need to create separate, identical implementations for the same
  algorithm that vary only by the constancy of buf simply so the compiler can
  optimize differently for each aspect is horrible.

Stephen addressed that very problem in the thread "const debacle". He came up with a solution, which I later simplified. It's probably not something that will happen any time soon, but just to let you know, it has been thought about, and a solution proposed.
  I would much rather have
  the compiler invisibly generate the different permutations for me and do
  something fancy with the name mangling to sort out all out invisibly.  So:

  "abc".find( 'b' ); // calls the "invariant(char)[]" permutation
  char[] buf; buf.find( 'b' ); // calls the "const(char)[]" permutation

Yep, that's what we solved. :-)
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Janice Caron <caron800 googlemail.com> wrote:
 Yep, that's what we solved. :-)

Ooh - actually, no. I stand corrected. You're returning a size_t. In that case, please ignore my previous post. Your template works just fine. Why don't you like it?
Mar 28 2008
prev sibling next sibling parent "Scott S. McCoy" <tag cpan.org> writes:
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


On Sat, 2008-03-29 at 12:13 -0700, Walter Bright wrote:

 It's like (well, not as bad as) exchanging the 
 meaning of the * and + operators.

We do this already...well not with arithmetic thank god, but with other operators. Take the infamous concatenation operator... PHP and Perl it's "." Pascal, Ruby, Pike, Python, Java, JavaScript, (and kind of in C++) it's "+" SQL and REXX it's "||" VB, Ada, AppleScript it's "&" but in D it's "~".... But in other languages, such as perl and AWK, ~ means something. It means "bind", as bind this regular expression: # awk if (foo ~ bar) { } # perl if ($foo ~= $bar) { } Similarly, this expression in AWK means something completely different in D: foobar = foo ~ bar; That being said, it doesn't really matter...it's a different language. Just like how "puede" means "it can" in spanish, but it means "can I" in tagalog. Anyway to that end, I don't think redefining const or creating a different work to mean const is any different than this. And it's a perfectly acceptable thing to do. After all, we're really trying to make "const" mean "from your view, this thing is constant" anyway, that's what it implies. Cheers, Scott S. McCoy
Mar 30 2008
prev sibling next sibling parent "Scott S. McCoy" <tag cpan.org> writes:
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


On Sat, 2008-03-29 at 00:05 -0700, Walter Bright wrote:

 Janice Caron wrote:
 I suggested that a declaration like
 
     const int x = 5;
 
 should be interpretted by the compiler as if the statement had been
 
     invariant int x = 5;
 

Yeah, but I can see the bug report now: "dammit, I typed it as const, why is it coming out as invariant?"

The last thing I want is for the compiler in a statically typed language to just decide to change my type for me.
Mar 30 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 30/03/2008, Janice Caron <caron800 googlemail.com> wrote:
 Perhaps, but I don't think you've understood that it is /impossible/
  to declare a const variable that isn't, in fact, invariant.

Sorry, let me qualify that. I was talking about POD types only - types which contain no pointers-to-mutable, and no pointers-to-const.
Mar 30 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 30/03/2008, Scott S. McCoy <tag cpan.org> wrote:
  On Sat, 2008-03-29 at 00:05 -0700, Walter Bright wrote:
  Janice Caron wrote:
 I suggested that a declaration like

 const int x = 5;

 should be interpretted by the compiler as if the statement had been

 invariant int x = 5;

Yeah, but I can see the bug report now: "dammit, I typed it as const, why is it coming out as invariant?" The last thing I want is for the compiler in a statically typed language to just decide to change my type for me.

Perhaps, but I don't think you've understood that it is /impossible/ to declare a const variable that isn't, in fact, invariant. Consider: const int x = 5; x may be typed const(int), but it is, in fact, really, really, invariant. Because not only can you not change it, but no one else can either. It obeys the contract for invariance. The compiler knows that, so should be able to take advantages of the optimization potential thereof. Furthermore, since invariant(int) implicitly casts to const(int), you won't even /notice/ that this has happened, unless you explicitly do writefln(typeof(x).stringof) or something. This is provably a completely safe thing to do, and would be transparent to the programmer apart from explicit type testing. (Plus, in combination of some of my other ideas, it could help us get rid of enum for manifest constants).
Mar 30 2008
prev sibling next sibling parent "Scott S. McCoy" <tag cpan.org> writes:
That is correct.

I'll try to remember to disable HTML formatting when submitting to a
news group.

Thanks.

On Sun, 2008-03-30 at 18:47 -0400, bearophile wrote:
 Scott S. McCoy Wrote:
 
 I see all your messages double, or I don't see their text at all... I think
you may be using HTML, and that may produce problems (I am using the web
interface on www.digitalmars.com/webnews/newsgroups.php ).
 
 Bye,
 bearophile

Mar 30 2008
prev sibling next sibling parent "Koroskin Denis" <2korden gmail.com> writes:
On Mon, 31 Mar 2008 02:47:58 +0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 Scott S. McCoy Wrote:

 I see all your messages double, or I don't see their text at all... I  
 think you may be using HTML, and that may produce problems (I am using  
 the web interface on www.digitalmars.com/webnews/newsgroups.php ).

 Bye,
 bearophile

Let me suggest you a newsreader! Not only it shows you unread messages, notifies when new messages arrive, works faster, uses less traffic, but allows you to follow discussion _much_ easier. A reader of my choice (and many others') is the one that integrated into Opera (the only browser I use).
Mar 31 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 31/03/2008, Roberto Mariottini <rmariottini mail.com> wrote:
  Well, so let's deprecate 'const' and use 'in' instead (this time I'm
  serious!).

That gets my vote!
Mar 31 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 27/04/2008, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:
  It's impossible? How about:
   const int x = someFuncThatReturnsConst();

x is still immutable.
  Your statement is only true if the said variable is static AND has an
 initializer.
  (also, to be more accurate, the type in the example should be changed to
 something other than a basic type like int)

Since the publication of accu-functional.pdf, we're all out of date here. Let's get back up to speed. Any type which contains no pointers to mutable data is implicitly castable to invariant. That's what I meant, but Andrei said it better! :-)
Apr 27 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Benji Smith wrote:
 STRINGS
 
 The existence of three different string types (six, if you count 
 const/mutable variations of each) makes text-processing more difficult 
 than it ought to be.

I have a hard time agreeing with that. While the multiple types give one options, you can just use one type (string) and ignore all the others. I've done string processing in D, and it's a LOT less work than in C++. Furthermore, the internationalization works, unlike C++. C++ won't save anyone from multiple string types. First of all, char types in C++ are implementation defined. The code doesn't work from one compiler to another. Next, C++0x is adding (you guessed it!) wchar and dchar types. C++0x will have char, signed char, unsigned char, wchar_t, char16_t, and char32_t as native types, plus volatile/const modifiers, making for 18 character types! Next, we have char[], vector<char>, and string<char>, making for 54 string types, more than half of which are implementation defined.
 I would have liked to see just one string type, with encoding kept as an 
 internal implementation detail.

That would be nice, but it is not practical for a systems programming language. The tradeoffs between char[], wchar[] and dchar[] are quite real and should be in the choice domain of the programmer.
 And I'd much rather have a string class 
 than to treat strings as character arrays

I can't think of any advantage for that.
 (especially since 
 indexing/slicing deals with code-points rather than character positions).

This is more of a theoretical problem than an actual one in my experience. For the cases where it is necessary, foreach (dchar c; s) ... will automatically decode UTF-8 strings quite nicely. Note that neither C++ nor Java handles this at all. Java tried to do it with 16 bit chars, but that got torpedoed when the Unicode standard adopted surrogate pairs. I consider the string support in D to be one of its great strengths. I've written text processing programs in D, including fully internationalized ones, and it's a breeze compared with doing it in C++ or Java. It runs faster, too!
Mar 27 2008
next sibling parent reply Michiel Helvensteijn <nomail please.com> writes:
Walter Bright wrote:

 making for 18 character types! Next, we have char[], vector<char>, and
 string<char>, making for 54 string types, more than half of which are
 implementation defined.

vector<char> is a silly example and you know it. You could have made your point just fine with only 36 string types. :-) I have to agree that C++ has a lot of baggage because of its backward compatibility. It is its greatest strength and its greatest weakness. -- Michiel
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michiel Helvensteijn wrote:
 Walter Bright wrote:
 
 making for 18 character types! Next, we have char[], vector<char>, and
 string<char>, making for 54 string types, more than half of which are
 implementation defined.

vector<char> is a silly example and you know it. You could have made your point just fine with only 36 string types. :-)

No, I don't agree that it is a silly example. Why is a string *fundamentally* different from an array? I believe it is a serious mistake to have both. I did throw a bone, though, by leaving off valarray<char> :-)
 I have to agree that C++ has a lot of baggage because of its backward
 compatibility. It is its greatest strength and its greatest weakness.

True, but that offers no reason to use C++ for new projects. Try writing an internationalized string processing app in C++, and you're in for endless pain and bugs.
Mar 27 2008
next sibling parent reply Michiel Helvensteijn <nomail please.com> writes:
Walter Bright wrote:

 making for 18 character types! Next, we have char[], vector<char>, and
 string<char>, making for 54 string types, more than half of which are
 implementation defined.

vector<char> is a silly example and you know it. You could have made your point just fine with only 36 string types. :-)

No, I don't agree that it is a silly example.

No one ever used vector<char> as a string and no one ever will.
 Why is a string *fundamentally* different from an array? I believe it is a
 serious mistake to have both. 

I agree. I like the D approach to strings a lot better than the C++ approach, as I said in another subthread.
 I did throw a bone, though, by leaving off valarray<char> :-)

Why not mention list<char> and deque<char> while you're at it? :-)
 I have to agree that C++ has a lot of baggage because of its backward
 compatibility. It is its greatest strength and its greatest weakness.

True, but that offers no reason to use C++ for new projects. Try writing an internationalized string processing app in C++, and you're in for endless pain and bugs.

There are toolkits like Qt that will make it a lot easier. Of course, the Qt toolkit does this by introducing yet another string type. ;-) -- Michiel
Mar 27 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michiel Helvensteijn wrote:
 No, I don't agree that it is a silly example.


Yet I'm always left wondering what is the difference between vector and string?
 Why is a string *fundamentally* different from an array? I believe it is a
 serious mistake to have both. 

I agree. I like the D approach to strings a lot better than the C++ approach, as I said in another subthread.
 I did throw a bone, though, by leaving off valarray<char> :-)

Why not mention list<char> and deque<char> while you're at it? :-)

Good idea!
 I have to agree that C++ has a lot of baggage because of its backward
 compatibility. It is its greatest strength and its greatest weakness.

an internationalized string processing app in C++, and you're in for endless pain and bugs.

There are toolkits like Qt that will make it a lot easier. Of course, the Qt toolkit does this by introducing yet another string type. ;-)

It seems like every C++ library has its own (incompatible) string type. I was motivated in D to make the string type good enough to not motivate people to invent string classes.
Mar 27 2008
next sibling parent reply Michiel Helvensteijn <nomail please.com> writes:
Walter Bright wrote:

 No, I don't agree that it is a silly example.


Yet I'm always left wondering what is the difference between vector and string?

The implementation may be the same. The difference is in the interface. std::basic_string<T> can concatenate, convert to c_str, find and extract substrings, etc. More importantly, it is well-behaved when sent to a stream. std::vector<T> is meant as a container for any type, and has iterators, push and pop functions.
 I have to agree that C++ has a lot of baggage because of its backward
 compatibility. It is its greatest strength and its greatest weakness.

an internationalized string processing app in C++, and you're in for endless pain and bugs.

There are toolkits like Qt that will make it a lot easier. Of course, the Qt toolkit does this by introducing yet another string type. ;-)

It seems like every C++ library has its own (incompatible) string type.

Qt softens the blow by having a implicit constructor that takes an std::string and a member-function toStdString().
 I was motivated in D to make the string type good enough to not motivate
 people to invent string classes.

What's good enough now may not be good enough in the future. And what's good enough for you may not be good enough for other programmers. By hard-coding certain behaviors in the core language, you've taken away the freedom of the programmer to choose these hirself. Like the growth-rate of dynamic arrays. Or the sorting algorithm used by the .sort property. Or the datastructure returned by the .keys property of associative arrays. I would still like to hear your views on my "library defines T[] and T[U]" idea. -- Michiel
Mar 27 2008
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Michiel Helvensteijn:
 freedom of the programmer to choose these hirself.

A hermaphrodite programmer even? :o) What an advanced newsgroup this is. Bye, bearophile
Mar 27 2008
parent Michiel Helvensteijn <nomail please.com> writes:
bearophile wrote:

 freedom of the programmer to choose these hirself.

A hermaphrodite programmer even? :o) What an advanced newsgroup this is.

I sometimes see "hirself" used instead of "him/herself", refering to a person who could be either male of female. But now that I've looked it up in the wiktionary, maybe I shouldn't use it like that anymore. ;-) -- Michiel
Mar 27 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Michiel Helvensteijn wrote:
 Walter Bright wrote:
 The implementation may be the same. The difference is in the interface.
 std::basic_string<T> can concatenate, convert to c_str, find and extract
 substrings, etc. More importantly, it is well-behaved when sent to a
 stream.

And why would one never want to concatenate arrays? Append a 0? Extract a sub-array? These distinctions are without a difference.
 std::vector<T> is meant as a container for any type, and has iterators, push
 and pop functions.

Bah, why cannot one iterate over the contents of a string? Why cannot one append a character to a string?
 I was motivated in D to make the string type good enough to not motivate
 people to invent string classes.

enough for you may not be good enough for other programmers.

Since D string is better than std::string and Java.lang.string on just about every aspect, it's hard to see how it's not good enough.
 By hard-coding certain behaviors in the core language, you've taken away the
 freedom of the programmer to choose these hirself. Like the growth-rate of
 dynamic arrays. Or the sorting algorithm used by the .sort property.

See Andrei's sort routines in std.algorithms. I don't think user extensibility is crippled at all.
 Or the
 datastructure returned by the .keys property of associative arrays.

The way AAs are implemented does not solve every issue with containers. But they are so convenient to use, and work well enough, that there just isn't enough juice left to make it worthwhile to do other container types.
 I would still like to hear your views on my "library defines T[] and T[U]"
 idea.

I just don't see the utility of it. It's often nice to have core features that are always there, always work, and always work across implementations, and 3rd party libraries will interoperate and they won't have to reinvent the wheel. Sometimes ubiquity is far more valuable than an extra erg of features or performance.
Mar 27 2008
parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Michiel Helvensteijn wrote:
 By hard-coding certain behaviors in the core language, you've taken away the
 freedom of the programmer to choose these hirself. Like the growth-rate of
 dynamic arrays. Or the sorting algorithm used by the .sort property.

extensibility is crippled at all.

I very much agree. See tango.core.Array for another set of algorithms specifically meant to extend the utility of built-in arrays: http://www.dsource.org/projects/tango/docs/current/tango.core.Array.html Since arrays already have the nifty trick where functions accepting them as the first argument can be used via the property syntax, the built-in arrays are far more flexible than any library type. The Tango Array module has basically every routine in <algorithm> plus a good number more, and the usage is specifically catered to work with slices. So you can do things like: auto buf = "hello world"; printf( "The slice up to 'el' in %.*s is: %.*s\n", buf, buf[0 .. buf.find( "el" )] ); std::equal_range can be duplicated by: buf[buf.lbound( 'e' ) .. buf.ubound( 'e' )]; // slice of lower to upper bound etc. The combination of good built-in arrays, the property syntax, and slicing makes for a top-notch combination. The <algorithm> stuff in C++ looks horrid by comparison. Sean
Mar 27 2008
prev sibling next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Michiel Helvensteijn wrote:
 Qt softens the blow by having a implicit constructor that takes an
 std::string and a member-function toStdString().

And the various string classes I've seen for D (usually called Text) have constructors or implicit casts from the various builtin string types.
 By hard-coding certain behaviors in the core language, you've taken away the
 freedom of the programmer to choose these hirself. Like the growth-rate of
 dynamic arrays. Or the sorting algorithm used by the .sort property. Or the
 datastructure returned by the .keys property of associative arrays.

No, it just means that most reasonable usage will have much cleaner syntax. It just means that code is more interoperable and more portable. If a programmer wants more control over their basic data structures, they can write their own or find a library solution. But for most applications, for most libraries, D's builtin arrays do at least as well as Java's or C#'s list classes, and its associative arrays as well as their dictionaries. And if these were library types, the exact same properties would hold. Of course, a huge bonus for having these built in is that you can have literals. In C#, you don't have dictionary literals; at my job we have a hack that looks like: -Using.Values["key", value]["key2", value2]; That's horrible compared to just ["key": value, "key2": value2];.
Mar 27 2008
prev sibling parent reply Georg Wrede <georg nospam.org> writes:
Michiel Helvensteijn wrote:
 By hard-coding certain behaviors in the core language, you've taken away the
 freedom of the programmer to choose these hirself. Like the growth-rate of
 dynamic arrays. Or the sorting algorithm used by the .sort property. Or the
 datastructure returned by the .keys property of associative arrays.

These could be parameterizable. (Like the growth-rate of dynamic arrays, etc.) At this stage of D, however, it may be more practical to have them chiseled in stone for the time being, letting us concentrate on more current and/or pressing issues. Of course, later (when most of the more pressing issues are solved) one could be interested in parameterizing these. (Or simply tuning them to get them exactly right.) And of course, nothing stands in the way of somebody writing a superior implementation of these, already today. Or the other (today-considered) basic data structures. Actually, if somebody does this, chances are they'd be incorporated into D. We've seen plenty of examples of somebody writing an excellent module that's later been incorporated into Phobos. And there's a lot of room for potential writers: currently std.algorithm does not contain next_permutation or prev_permutation. Not to mention all the things one wouldn't guess off-hand. Or the things that really make a difference, like something fiercely usable, that we've simply ignored so far. Additionally, since the front-end of D is public domain, you may read, copy, modify, and eventually even return the derived contributions to the community. In other words, if the datastructure returned by .keys is inadequate, copy it off of the library, and enhance it. When you're satisfied, simply send it to Walter, or publish it here to get some feedback.
Mar 27 2008
parent bearophile <bearophileHUGS lycos.com> writes:
Georg Wrede:
 In other words, if the datastructure returned by .keys is 
 inadequate, copy it off of the library, and enhance it.

I think the D built-ins (like the .keys of AAs) may enjoy receiving a strong push toward laziness, see for example lot of the x-functions in my libs, or dicts in Python 3.0: http://www.python.org/dev/peps/pep-3106/ Bye, bearophile
Mar 28 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 Yet I'm always left wondering what is the difference between vector and
 string?

In Microsoft Visual Studio's implementation, std::string implements copy-on-write, wheras std::vector doesn't. e.g. std::vector<char> v1 = whatever; std::vector<char> v2 = v1; // makes a copy std::string s1 = whatever; std::string s2 = s1; // no copy made, YET s2[0] = 'x'; // NOW a copy is made This is purely an implementation difference. It is not specified in the standard. D takes a sort of halfway-in-between approach. In D, we copy arrays (including strings) by reference, and implement copy-on-write in the algorithms; In MSVC++ one copies vectors and string by value, and copy-on-write is implemented in the design of std::string.

Making strings arrays of invariant makes them implicitly copy-on-write. More generally, whether D arrays are copy-on-write or not is based on whether the element type is invariant or mutable. It isn't based on if the contents are text or not.
Mar 28 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 Making strings arrays of invariant makes them implicitly copy-on-write.

We're drifting off topic here, but ... I don't think that's right. Example: string s = "hello"; string t = std.string.replace(s,"x","y"); assert(s == t); // OK assert(s is t); // *FAILS* This example demonstrates that std.string.replace() does not do copy-on-write. (Instead, it does copy-always). Thus, as I was saying, whether or not copy-on-write is done is part of the algorithm, not part of the type.

Ok, that's true up to a point. COW implies you *must* copy it if you change it, but copying it anyway doesn't really break COW, it's just inefficient.
  More generally, whether D arrays are copy-on-write or not is based on
  whether the element type is invariant or mutable.

Again, it is /possible/ to implement copy-on-write using mutable strings (as MSVC++ std::string proves) - just very difficult. But D's immutable makes it easy.

D 1.0 also has COW with mutable types, but the problem with it was you had to rely heavily on the programmer to not make a mistake with it. This led to code that excessively dup'd strings "just to be sure."
 It isn't based on if
 the contents are text or not.

No argument there! :-)

Then I guess we close with still no particular reason why strings and vectors cannot be the same!
Mar 28 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Janice Caron (caron800 googlemail.com)'s article
 On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 Yet I'm always left wondering what is the difference between vector and
 string?

copy-on-write, wheras std::vector doesn't.

I'm sorry, but unless I missed a memo, this hasn't been the case for probably ten years. It's been shown fairly conclusively that STL-conformant COW strings are incompatible with multithreaded programs, and Dinkumware has long since switched them for a non-COW design. Did they change them back with VS 8.x? Personally, I think the difference between vector and string is largely in the operations they support. Here are the gaps, from a quick glance at the standard: vector: back front pop_back string: append c_str compare copy data find find_first_not_of find_first_of find_last_not_of find_last_of length npos operator+= operator= replace rfind substr The important thing to note about the routines added to string (such as find) is that they have overloads which accept value_type* as an argument, for easy integration with C-style strings. c_str and data are much the same, and one can assert that strings may always be ordered while vectors may not (ie. compare). Overall though, I find the D approach to make more sense. Strings are really just a sequence of characters, so why bother with two separate containers? However, I wouldn't be surprised if a redesign today did something along these lines as well, and relied on <algorithm> plus perhaps some helper functions to handle the various operations currently embedded for convenience in the classes themselves. Sean
Mar 28 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Janice Caron (caron800 googlemail.com)'s article
 I'm sure that's how it works - at least in Visual Studio 6 and 7. But
 feel free to tell me if I'm wrong.

Perhaps you're right. It's certainly not what I remember, but then I haven't done Windows development for probably five years now so perhaps the MS impl has changed. I'll admit to being somewhat surprised however. Sean
Mar 28 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 It's been shown fairly conclusively that STL-conformant COW strings
 are incompatible with multithreaded programs,

This is what I was alluding to when I said that the C++ community knows there are fundamental problems with C++ and multithreading, and that C++ const is one of the culprits. I don't think C++0x addresses this at all.
Mar 28 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 It's been shown fairly conclusively that STL-conformant COW strings
 are incompatible with multithreaded programs,

there are fundamental problems with C++ and multithreading, and that C++ const is one of the culprits. I don't think C++0x addresses this at all.

It doesn't. Frankly, I think the multithreading features in C++ 0x are too little too late. They'll probably make maintaining old code a bit easier, and perhaps buy the language an extra five years of mainstream relevance while people struggle to make it work, but the changes still only bring C++ up to where Java was when JSR-133 was published some five (?) years ago. And by the time compilers are 0x compliant I wouldn't be half surprised for the average PC to contain 8 cores and for lock-based programming to be well on its way out. Sean
Mar 28 2008
parent reply Tim Burrell <tim timburrell.net> writes:
Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 It's been shown fairly conclusively that STL-conformant COW strings
 are incompatible with multithreaded programs,

there are fundamental problems with C++ and multithreading, and that C++ const is one of the culprits. I don't think C++0x addresses this at all.

It doesn't. Frankly, I think the multithreading features in C++ 0x are too little too late. They'll probably make maintaining old code a bit easier, and perhaps buy the language an extra five years of mainstream relevance while people struggle to make it work, but the changes still only bring C++ up to where Java was when JSR-133 was published some five (?) years ago. And by the time compilers are 0x compliant I wouldn't be half surprised for the average PC to contain 8 cores and for lock-based programming to be well on its way out.

Everyone here seems quick to point the finger at C++0x for not doing more with working toward good parallel support. But we're not really addressing the point that even disregarding C++0x, C++ _already_ has WAY better parallel support than D does via OpenMP (which is available on nearly every C++ compiler). Agreed the upcoming C++0x features are pretty lame -- they should have just merged the OpenMP 3 draft into the C++0x draft, but never the less, D is really falling way behind here. When C++0x comes out, combined with OpenMP, D won't even be close to being a viable language for parallel development... unless of course gdc can leverage some of gcc's (>= 4.2) OpenMP support maybe?
Mar 28 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Tim Burrell (tim timburrell.net)'s article
 Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 It's been shown fairly conclusively that STL-conformant COW strings
 are incompatible with multithreaded programs,

there are fundamental problems with C++ and multithreading, and that C++ const is one of the culprits. I don't think C++0x addresses this at all.

It doesn't. Frankly, I think the multithreading features in C++ 0x are too little too late. They'll probably make maintaining old code a bit easier, and perhaps buy the language an extra five years of mainstream relevance while people struggle to make it work, but the changes still only bring C++ up to where Java was when JSR-133 was published some five (?) years ago. And by the time compilers are 0x compliant I wouldn't be half surprised for the average PC to contain 8 cores and for lock-based programming to be well on its way out.

more with working toward good parallel support. But we're not really addressing the point that even disregarding C++0x, C++ _already_ has WAY better parallel support than D does via OpenMP (which is available on nearly every C++ compiler).

Hogwash. C++ has no in-language support for multithreading at all. OpenMP is simply a library built on top of C++. It doesn't count. One could create the exact same thing for D. Heck, D already has futures, DSCP, a good collection of synchronization primitives (tango.core.sync), etc.
 When C++0x comes out, combined with OpenMP, D won't even be close to
 being a viable language for parallel development... unless of course gdc
 can leverage some of gcc's (>= 4.2) OpenMP support maybe?

I disagree. D already has basically everything C++ 0x will have in terms of multithreaded support and it has them now. The only advantage C++ will have is a well-defined multithreaded memory model, and by the time anyone actually supports it for C++ 0x I suspect we'll have something equivalent in D. Also, D does have a "volatile" statement which accomplishes much the same thing as the multithreaded memory model in C++. It's much more low- level, but does allow a library writer to create correct, language-conformant lock-free code. See tango.core.Atomic, for example. Tango has had the Atomic module since its release over a year ago, and it's much the same as what the C++ committee has decided upon for 0x even with the language changes. That said, I should qualify the above by saying that I don't consider the state of C++ to be at all reflective of the abilities or the desire of anyone on the committee, but rather an artifact of the glacially slow standardization process as well as a basic requirement of backwards-compatibility. The combination of these factors pretty much guarantees that C++ will never look very different than it does today regardless of what would be best for its ability to solve new problems in the future. By contrast, if Walter decided to morrow that he wanted D to become a purely functional language with write-once variables then he could do so, even if it meant breaking every program ever written for D. Sean
Mar 28 2008
parent reply Tim Burrell <tim timburrell.net> writes:
Sean Kelly wrote:
 Hogwash.  C++ has no in-language support for multithreading at all.  OpenMP
 is simply a library built on top of C++.  It doesn't count.  One could create
the
 exact same thing for D.  Heck, D already has futures, DSCP, a good collection
 of synchronization primitives (tango.core.sync), etc.

Since you're allowing Tango library features you might as well allow Boost to be included with C++. Even if you don't, really what I'm intending to compare is a typical usage scenario for parallel programming in D and C++. With C++ you've got scoped mutexes and every multithreading thing you'd need (all cross platform) via Boost... PLUS you've got OpenMP support which is NOT just a simple library built on top of C++. OpenMP does include a library API, yes, but mostly it's compiler directives... this allows the compiler to optimize certain types of operations based on static analysis, architecture features, etc... something that'll be much harder to do via a simple library implementation. This type of stuff really needs to be in the compiler, and that's precisely where it is with OpenMP. Unless D adopts a similar strategy it will never be able to compete. At any rate, I didn't want this to be a C++ is better than D flame war kind of thing, I just wanted to point out that unless D gets some really good parallel support (and soon!) it's not going to continue to be as interesting as it currently is!
 When C++0x comes out, combined with OpenMP, D won't even be close to
 being a viable language for parallel development... unless of course gdc
 can leverage some of gcc's (>= 4.2) OpenMP support maybe?

I disagree. D already has basically everything C++ 0x will have in terms of multithreaded support and it has them now. The only advantage C++ will have is a well-defined multithreaded memory model, and by the time anyone actually supports it for C++ 0x I suspect we'll have something equivalent in D.

OpenMP, OpenMP, OpenMP. D won't have OpenMP (or something like it). That's what I want to hit home. Yes you're absolutely correct that D already has everything C++0x will have in terms of native multithreading, and while those things are a necessity they aren't getting us any closer to a good model for parallel programming. OpenMP isn't the be-all / end-all, there's tons of other interesting stuff out there (join-calculus comes to mind), but it's a good start, and without something like it (in terms of compiler support) D isn't even a contender when it comes to parallel development.
Mar 28 2008
parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Tim Burrell (tim timburrell.net)'s article
 Sean Kelly wrote:
 Hogwash.  C++ has no in-language support for multithreading at all.  OpenMP
 is simply a library built on top of C++.  It doesn't count.  One could create
the
 exact same thing for D.  Heck, D already has futures, DSCP, a good collection
 of synchronization primitives (tango.core.sync), etc.

Boost to be included with C++. Even if you don't, really what I'm intending to compare is a typical usage scenario for parallel programming in D and C++. With C++ you've got scoped mutexes and every multithreading thing you'd need (all cross platform) via Boost... PLUS you've got OpenMP support which is NOT just a simple library built on top of C++. OpenMP does include a library API, yes, but mostly it's compiler directives... this allows the compiler to optimize certain types of operations based on static analysis, architecture features, etc...

So you're saying that OpenMP is both a library and a language extension (using double-lowercase-prefixed keyword I assume, for coformance)? That's fine, but I'm not sure I see how this will change with C++ 0x.
 something that'll be much harder to do via a simple library
 implementation.  This type of stuff really needs to be in the compiler,
 and that's precisely where it is with OpenMP.  Unless D adopts a similar
 strategy it will never be able to compete.
 At any rate, I didn't want this to be a C++ is better than D flame war
 kind of thing, I just wanted to point out that unless D gets some really
 good parallel support (and soon!) it's not going to continue to be as
 interesting as it currently is!

I agree with that.
 When C++0x comes out, combined with OpenMP, D won't even be close to
 being a viable language for parallel development... unless of course gdc
 can leverage some of gcc's (>= 4.2) OpenMP support maybe?

I disagree. D already has basically everything C++ 0x will have in terms of multithreaded support and it has them now. The only advantage C++ will have is a well-defined multithreaded memory model, and by the time anyone actually supports it for C++ 0x I suspect we'll have something equivalent in D.

That's what I want to hit home. Yes you're absolutely correct that D already has everything C++0x will have in terms of native multithreading, and while those things are a necessity they aren't getting us any closer to a good model for parallel programming. OpenMP isn't the be-all / end-all, there's tons of other interesting stuff out there (join-calculus comes to mind), but it's a good start, and without something like it (in terms of compiler support) D isn't even a contender when it comes to parallel development.

Thanks for clearing this up. Sean
Mar 28 2008
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
Michiel Helvensteijn wrote:
 Walter Bright wrote:
 
 making for 18 character types! Next, we have char[], vector<char>, and
 string<char>, making for 54 string types, more than half of which are
 implementation defined.

point just fine with only 36 string types. :-)


No one ever used vector<char> as a string and no one ever will.

"If you are running in a multithreaded environment where you've determined that string's reference counting support is a performance problem... consider using vector<char> instead of string." -- Scott Meyers, "Effective STL", p 65.
Apr 01 2008
parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Don Clugston (dac nospam.com.au)'s article
 Michiel Helvensteijn wrote:
 Walter Bright wrote:

 making for 18 character types! Next, we have char[], vector<char>, and
 string<char>, making for 54 string types, more than half of which are
 implementation defined.

point just fine with only 36 string types. :-)


No one ever used vector<char> as a string and no one ever will.

string's reference counting support is a performance problem... consider using vector<char> instead of string." -- Scott Meyers, "Effective STL", p 65.

It's also quite handy in instances where a writeable char ptr must be passed to a C function: std::vector<char> buf( SIZE ); strcpy( &buf[0], "hello, world!" ); Can't do that with std::string, and using new[]/delete[] isn't exception safe. Sean
Apr 01 2008
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2008-03-27 18:17:40 -0400, Walter Bright <newshound1 digitalmars.com> said:

 Michiel Helvensteijn wrote:
 Walter Bright wrote:
 
 making for 18 character types! Next, we have char[], vector<char>, and
 string<char>, making for 54 string types, more than half of which are
 implementation defined.

vector<char> is a silly example and you know it. You could have made your point just fine with only 36 string types. :-)

No, I don't agree that it is a silly example. Why is a string *fundamentally* different from an array? I believe it is a serious mistake to have both.

std::string is null terminated in its memory representation; that's why you can call s.c_str() and have a char * that lives as long as you don't cause the string to reallocate. So basically, std::string can be freely converted to a C string if you need one. With std::vector and others you don't have that. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Mar 28 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Janice Caron (caron800 googlemail.com)'s article
 On 28/03/2008, Michel Fortin <michel.fortin michelf.com> wrote:
 std::string is null terminated in its memory representation;

standard. All that is guaranteed is that std::string::c_str() must return a null-terminated char array. The standard does not mandate how that happens, however.

It does require the returned array to be valid until the string is mutated IIRC, and that makes null termination of the data the most expedient implementation, even if it isn't required. The data in string isn't required to be contiguous either (unlike vector), though I believe this may have changed in C++ 0x. Sean
Mar 28 2008
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Michel Fortin wrote:
 std::string is null terminated in its memory representation; that's why 
 you can call s.c_str() and have a char * that lives as long as you don't 
 cause the string to reallocate. So basically, std::string can be freely 
 converted to a C string if you need one. With std::vector and others you 
 don't have that.

That's easy to accomplish with a vector implementation - just append a 0.
Mar 28 2008
prev sibling parent Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Michel Fortin wrote:
 On 2008-03-27 18:17:40 -0400, Walter Bright <newshound1 digitalmars.com> 
 said:
 
 Michiel Helvensteijn wrote:
 Walter Bright wrote:

 making for 18 character types! Next, we have char[], vector<char>, and
 string<char>, making for 54 string types, more than half of which are
 implementation defined.

vector<char> is a silly example and you know it. You could have made your point just fine with only 36 string types. :-)

No, I don't agree that it is a silly example. Why is a string *fundamentally* different from an array? I believe it is a serious mistake to have both.

std::string is null terminated in its memory representation; that's why you can call s.c_str() and have a char * that lives as long as you don't cause the string to reallocate. So basically, std::string can be freely converted to a C string if you need one. With std::vector and others you don't have that.

There is no guarantee in the C++ standard that std::string is null-terminated in its memory representation.
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 Yet I'm always left wondering what is the difference between vector and
 string?

In Microsoft Visual Studio's implementation, std::string implements copy-on-write, wheras std::vector doesn't. e.g. std::vector<char> v1 = whatever; std::vector<char> v2 = v1; // makes a copy std::string s1 = whatever; std::string s2 = s1; // no copy made, YET s2[0] = 'x'; // NOW a copy is made This is purely an implementation difference. It is not specified in the standard. D takes a sort of halfway-in-between approach. In D, we copy arrays (including strings) by reference, and implement copy-on-write in the algorithms; In MSVC++ one copies vectors and string by value, and copy-on-write is implemented in the design of std::string.
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 Making strings arrays of invariant makes them implicitly copy-on-write.

We're drifting off topic here, but ... I don't think that's right. Example: string s = "hello"; string t = std.string.replace(s,"x","y"); assert(s == t); // OK assert(s is t); // *FAILS* This example demonstrates that std.string.replace() does not do copy-on-write. (Instead, it does copy-always). Thus, as I was saying, whether or not copy-on-write is done is part of the algorithm, not part of the type. Of course, std.string.replace() could be rewritten to implement copy-on-write, but that would kinda prove my point. Invariant arrays make copy-on-write /possible/, but they don't make it mandatory.
  More generally, whether D arrays are copy-on-write or not is based on
  whether the element type is invariant or mutable.

Again, it is /possible/ to implement copy-on-write using mutable strings (as MSVC++ std::string proves) - just very difficult. But D's immutable makes it easy.
 It isn't based on if
 the contents are text or not.

No argument there! :-)
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
  Then I guess we close with still no particular reason why strings and
  vectors cannot be the same!

Yep. I'm in complete and full agreement with you. I only posted at all because I thought you were asking what the difference was /in C++/. Whether or not those differences are justified is another question entirely, and on that one, I completely agree with you.
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Michel Fortin <michel.fortin michelf.com> wrote:
 std::string is null terminated in its memory representation;

No, that's an implementation detail. It's not guaranteed by the C++ standard. All that is guaranteed is that std::string::c_str() must return a null-terminated char array. The standard does not mandate how that happens, however. In particular, the following is not legal std::string s = "hello"; char c = s[5]; There is no guarantee that c will be assigned '\0'. (although it will probably work anyway).
Mar 28 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 28/03/2008, Sean Kelly <sean invisibleduck.org> wrote:
 I'm sorry, but unless I missed a memo, this hasn't been the case for probably
  ten years.

In Microsoft's implementation of std::string, there is a one-byte reference count immediately preceeding the first char. So if you do std::string s = "hello"; then somewhere in memory (in fact, at (&s[0])-1), there will be an array [ 1, 'h', 'e', 'l', 'l', 'o', 0 ], If you then do std::string t = s; then that array changes to [ 2, 'h', 'e', 'l', 'l', 'o', 0 ], but no copy of the string data is made. If you then modify one of the strings s[0] = 'j'; then a new array is constructed, pointers are moved about, counters are decremented, and you end up with s having an array of [ 1, 'j', 'e', 'l', 'l', 'o', 0 ] and t having a brand new array of [ 1, 'h', 'e', 'l', 'l', 'o', 0 ]. The process stops when the reference counter reaches 254. A value of 255 is special, and means "always copy". Also, these things contain a lock to keep them thread-safe. I'm sure that's how it works - at least in Visual Studio 6 and 7. But feel free to tell me if I'm wrong.
Mar 28 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Benji Smith wrote:
 ARRAYS
 
 1) There's a gap in functionality between static arrays (whose size must 
 be known at compile time) and growable dynamic arrays.
 
 Most often, what I really want is a non-growable array whose size isn't 
 known until runtime, but D doesn't have that concept (Java and .NET have 
 it).

Java has the opposite issue - arrays cannot be grown at all. You have to allocate/copy the entire array every time. Andrei did propose a non-growable array last summer, but there was little interest in it.
 And the disparity between the static & dynamic array types (which 
 are fundamentally different in the type system) means I can't write code 
 like this:
 
   int[] doSomething(int[] array) { ... }
 
   int[4] a;
   int[] b;
 
   // Inplicit conversion. Does this copy data?
   b = doSomething(a);
 
   // Error: functions can't return fixed-length arrays!
   a = doSomething(b);
 
 That's really too bad. The type system really should treat an int[] and 
 an int[4] as the same type.

Actually, what we're going towards is having static arrays be value types, like structs are. This might be what you're asking for, although it would increase the semantic difference between T[] and T[4].
 If the compiler wants to optimize certain 
 static arrays by putting them in the data section of the compiled OBJ, 
 when possible, that's fine by me. But having that behavior affect the 
 type system is a pain in the neck.
 
 I also would have preferred to have growable arrays and associative 
 arrays in the standard library than in the language. A more unified 
 array syntax could get rid of some nasty warts like this:
 
   // Doesn't compile
   char[][] words = [ "hello", "world" ];
 
   // Compiles, but the only way to know about this trick is by asking
   // someone for help in the NG.
   char[][] words = [ "hello"[], "world" ];

That is just a fixable wart, not a fundamental issue.
   // Would be ideal. Growable arrays would be best implemented as a
   // templatized collection class.
   List!(String) words = [ "hello, "world" ];
 
 2) An empty array is equal to a null pointer. Yikes!

Not exactly, although a null array is also an empty array, the reverse is not true.
 3) Array syntax should support both multi-dimensional arrays and jagged 
 arrays:
 
   int[,] multidim = new int[4,5];
   int[][] jagged = new int[4][5];

I agree that would be nice, but C++ doesn't do it either.
Mar 27 2008
next sibling parent reply Georg Wrede <georg nospam.org> writes:
Walter Bright wrote:
 Benji Smith wrote:
 3) Array syntax should support both multi-dimensional arrays and 
 jagged arrays:

   int[,] multidim = new int[4,5];
   int[][] jagged = new int[4][5];

I agree that would be nice, but C++ doesn't do it either.

Ehh, I know this was positioned as a defensive post. But still, shouldn't we drop the "but C++ doesn't do it either" stuff? At the very least, it'd need an additional qualifier, right? Or else there'd be no point in having D in the first place.
Mar 27 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Georg Wrede wrote:
 But still, shouldn't we drop the "but C++ doesn't do it either" stuff?

I use it when I hear things like "this is unusable" and "so I'll use C++ instead" <g>. Otherwise, I agree that we should be working towards making D as good as possible regardless of the failings of other languages.
Mar 27 2008
parent reply Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Walter Bright wrote:
 Georg Wrede wrote:
 But still, shouldn't we drop the "but C++ doesn't do it either" stuff?

I use it when I hear things like "this is unusable" and "so I'll use C++ instead" <g>. Otherwise, I agree that we should be working towards making D as good as possible regardless of the failings of other languages.

I would also like to support the idea that denigrating C++, unfairly and with an obvious bias, is not the way to promote your ideas in D in any way and will just lose for D the interest of intelligent people who would otherwise be interested in at least trying it out and contributing to ideas of what it might be.
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Edward Diener wrote:
 Walter Bright wrote:
 Georg Wrede wrote:
 But still, shouldn't we drop the "but C++ doesn't do it either" stuff?

I use it when I hear things like "this is unusable" and "so I'll use C++ instead" <g>. Otherwise, I agree that we should be working towards making D as good as possible regardless of the failings of other languages.

I would also like to support the idea that denigrating C++, unfairly and with an obvious bias, is not the way to promote your ideas in D in any way and will just lose for D the interest of intelligent people who would otherwise be interested in at least trying it out and contributing to ideas of what it might be.

Yet at some point one does have to answer the question why one should bother with D when there's C++?
Mar 28 2008
parent reply Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Walter Bright wrote:
 Edward Diener wrote:
 Walter Bright wrote:
 Georg Wrede wrote:
 But still, shouldn't we drop the "but C++ doesn't do it either" stuff?

I use it when I hear things like "this is unusable" and "so I'll use C++ instead" <g>. Otherwise, I agree that we should be working towards making D as good as possible regardless of the failings of other languages.

I would also like to support the idea that denigrating C++, unfairly and with an obvious bias, is not the way to promote your ideas in D in any way and will just lose for D the interest of intelligent people who would otherwise be interested in at least trying it out and contributing to ideas of what it might be.

Yet at some point one does have to answer the question why one should bother with D when there's C++?

You can answer that question within any context without having to skew your argument against C++, and if the answer is that their is no advantage in using D over C++ it does not negate the areas where there may be advantages.
Mar 28 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Edward Diener wrote:
 You can answer that question within any context without having to skew 
 your argument against C++, and if the answer is that their is no 
 advantage in using D over C++ it does not negate the areas where there 
 may be advantages.

What should I say to someone who says something like: "D is unusable because it offers no protection against integer overflows, so I'll stick with C++" ?
Mar 28 2008
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Koroskin Denis:
 You said, no protection against integer overflows in D? You are wrong!
 Permission to add this to Phobos is granted!

I think we may need something faster (inlined) and more automatic (better supported by the compiler). Bye, bearophile
Mar 29 2008
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Koroskin Denis wrote:
 Permission to add this to Phobos is granted!

Your solution is actually kind of cool! I certainly never thought of it.
Mar 29 2008
prev sibling parent reply Georg Wrede <georg nospam.org> writes:
Janice Caron wrote:
 On 29/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
 
 What should I say to someone who says something like: "D is
 unusable because it offers no protection against integer overflows,
 so I'll stick with C++" ?

I honestly don't see a problem with the response "C++ can't do that either". That's not C++ bashing, that's challenging an assertion.

Here I'd agree with you.
 Basically, I disagree with Georg.

However, my exception was to "dismissal by hand waving". (And the above context is not what the below one was, to which I did object.) Walter Bright wrote:
 Benji Smith wrote:

 3) Array syntax should support both multi-dimensional arrays and jagged arrays:

   int[,] multidim = new int[4,5];
   int[][] jagged = new int[4][5];

I agree that would be nice, but C++ doesn't do it either.

- Mom, I wish you'd have ketchup in the fridge. - Thad'd be nice, but people in Nepal don't have it either.
Mar 29 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Georg Wrede wrote:
  - Thad'd be nice, but people in Nepal don't have it either.

If you go back in the thread, the poster was going to stick with C++, so for the listed faults in D it is legitimate to point out the ones that are shared with C++.
Mar 30 2008
parent Georg Wrede <georg nospam.org> writes:
Walter Bright wrote:
 Georg Wrede wrote:
 
  - Thad'd be nice, but people in Nepal don't have it either.

If you go back in the thread, the poster was going to stick with C++, so for the listed faults in D it is legitimate to point out the ones that are shared with C++.

Ok.
Mar 30 2008
prev sibling next sibling parent "Scott S. McCoy" <tag cpan.org> writes:
Content-Type: text/plain
Content-Transfer-Encoding: 7bit


On Fri, 2008-03-28 at 20:25 -0700, Walter Bright wrote:

 Edward Diener wrote:
 You can answer that question within any context without having to skew 
 your argument against C++, and if the answer is that their is no 
 advantage in using D over C++ it does not negate the areas where there 
 may be advantages.

What should I say to someone who says something like: "D is unusable because it offers no protection against integer overflows, so I'll stick with C++" ?

For this one, I tend to go with nothing at all. Anyone making such a discordant statement is, well, being too retarded to even respond to. :-)
Mar 28 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 29/03/2008, Walter Bright <newshound1 digitalmars.com> wrote:
  What should I say to someone who says something like: "D is unusable
 because it offers no protection against integer overflows, so I'll stick
 with C++" ?

I honestly don't see a problem with the response "C++ can't do that either". That's not C++ bashing, that's challenging an assertion. Basically, I disagree with Georg. It's propositional calculus, plain and simple. If someone says "X implies Y", one should be allowed to respond with "X is false".
Mar 29 2008
prev sibling next sibling parent "Koroskin Denis" <2korden gmail.com> writes:
On Sat, 29 Mar 2008 06:25:04 +0300, Walter Bright  =

<newshound1 digitalmars.com> wrote:

 Edward Diener wrote:
 You can answer that question within any context without having to ske=


 your argument against C++, and if the answer is that their is no  =


 advantage in using D over C++ it does not negate the areas where ther=


 may be advantages.

What should I say to someone who says something like: "D is unusable =

 because it offers no protection against integer overflows, so I'll sti=

 with C++" ?

You said, no protection against integer overflows in D? You are wrong! import std.stdio; import std.traits; Integral checked(Integral)(lazy Integral dg) { static assert(isIntegral!(Integral)); Integral result =3D dg(); asm { jo overflow; } return result; overflow: throw new Exception("Integer overflow occured"); } int main() { int t =3D int.max; try { int s =3D checked(t + 1); writefln("Result is %d", s); } catch(Exception e) { writefln("Whoops! %s", e.toString()); } return 0; } Permission to add this to Phobos is granted!
Mar 29 2008
prev sibling parent "Koroskin Denis" <2korden gmail.com> writes:
On Sat, 29 Mar 2008 18:29:40 +0300, bearophile <bearophileHUGS lycos.com=
  =

wrote:
 Koroskin Denis:
 You said, no protection against integer overflows in D? You are wrong=


 Permission to add this to Phobos is granted!

I think we may need something faster (inlined) and more automatic =

 (better supported by the compiler).

 Bye,
 bearophile

Well, yes. This function should be automatically inlined by a compiler. And I doubt we need implicit integer overflow checking, because it makes= = noticable slowdown and not always desirable. However, I'd like to see more language support too. I believe the way it= 's = done in C# is just what we need: "The checked(unchecked) keyword is used to control the overflow-checking= = context for integral-type arithmetic operations and conversions." "In a checked context, if an expression produces a value that is outside= = the range of the destination type, the result depends on whether the = expression is constant or non-constant. Constant expressions cause compi= le = time errors, while non-constant expressions are evaluated at run time an= d = raise exceptions." "If neither checked nor unchecked is used, a constant expression uses th= e = default overflow checking at compile time, which is checked. Otherwise, = if = the expression is non-constant, the run-time overflow checking depends o= n = other factors such as compiler options and environment configuration." checked { int i =3D int.max; ++i; // throws an exception } int t =3D int.max; int s =3D checked(t + 1); // the same goes here checked { int i =3D int.max; unchecked { int t =3D i + 1; // but no exception here } } int main() { static const int i1 =3D int.max + 1; // compile-time e= rror = here static const int i2 =3D unchecked(int.max + 1); // but ok here } As of now, we have no language support for this and my checked() trick i= s = the only way to go.
Mar 29 2008
prev sibling next sibling parent Georg Wrede <georg nospam.org> writes:
Benji Smith wrote:
 I first stumbled across the D programming language way back in 2002.

Long time, no see, Benji! Congrats on the kids! My youngest was born after I got into D, and this year she'll start school. Man, doesn't time fly!
 But the language was *ALMOST* ready.

True! And had we then known that in 2008 it still is, many of us would be long gone. OTOH, D really is a lot better now.
 Here are some of the things that are most offputting:

Must say that I agree with almost all of it! D1 is what you'd be interested in. I just looked at the differences between D1 and D2, and found that there's almost nothing I'd honestly need *when developing for customers*. And it's spec is _very_ stable, almost paranoidly so. D1 is a long-term thing. It's good enough for what one might expect today, and the stability offers tool and library writers a chance to write code without chasing a moving target. Also by this time, you probably don't stumble on bugs unless you do something very unusual. And it keeps getting bug fixes, at least until D3 (experimental) is announced, AND when D2 becomes stable enough for library writers and serious app writers to have moved to. As to D2, for me it's mostly for playing with the language and concepts, and generally having a toy that keeps feeling "new". ;-) It also keeps up the interest and excitement of being on the bleeding edge of language development. But still, your points on D were well thought out and valid. I sure hope they make a difference here.
Mar 27 2008
prev sibling parent "Ralf Schneider" <ralfs72_at_ gmx.net> writes:
... I agree on all your points. I have switched back to C++ when the const 
debacle has started.
IMHO D is getting even more complicated (and make the compiler happy) than 
C++.
My current solution is to use C++ or Python + C.
But I still have some hope for D, otherwise I would have stopped reading the 
newsgroup.

- Ralf 
Mar 30 2008