www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - struct vs. class, int vs. char.

reply MLT <none anon.com> writes:
D is really an amazing language! It really is everything that C++ did not
manage to be, at least as far as my limited experience with it shows. 

I noticed a couple of "problems" with it, and wanted to comment on them. It
could easily be that these comments just stem from my ignorance.

1. struct vs. class
As far as I understand, these two reserved words, that in C++ mean very similar
things, in D are very different. A class variable is "really" a pointer,
whereas a struct is directly allocated memory.

What I don't like is that it seems that structs and classes should almost be
interchangeable - one might implement something as a class and later want it to
be a struct, or vice versa. It almost is actually a local decision. I might
want something to be a class in one place, and a struct in another.

And, it seems that struct and class refer to several different things: (1)
struct and class are allocated in different places, (2) struct is supposed to
ensure its structure, and (3) struct is copied by value, whereas class by
reference.
It seems to me that these are 3 different issues, and one should have control
over them separately.

I find this example a bit strange:
struct S { int x;}
class C {int x;}
void main() {
{
  S x ;
  x.x = 1 ;
  S y = x ;
  y.x =2 ;
  writefln(x.x) ; // x.x is 1
}
{
  C x = new C ;
  x.x = 1;
  C y = x ;
  y.x = 2 ;
  writefln(x.x) ; // x.x is 2
}
}

I would have preferred to declare directly that the variable y takes or doesn't
take a reference when assigned. Otherwise, it seems to me that a program that
uses both (struct and class) can get mightily confusing.
Maybe the solution is to not use struct (which is I guess what is recommended
unless you really need it.)


2. char[] vs. int[]
I think it is strange that 
char[] x = "1234" ;
x[0] = '4' ;

Produces a run time error, but
int[] x = [1,2,3,4] ;
x[0] = 4 ;
Doesn't. I think that they both should, or both shouldn't - to be consistent
(and it would be better if they both didn't). Best would be again, to allow the
programmer to specify where the array (or other stuff) should be stored.

3. Builtin types vs. classes
(Here I probably am just missing the right phobos reference). D's builtin
structures are very rich. Associative arrays with arbitrary keys! Given that,
it is even sadder than it is in C++, that one can not inherit from the basic
types. I want to implement something that is basically an associative array of
one of my classes, with additional features. To do that, I will probably have
to put the associative array as a component, and redefine all
components/operations, or inherit from an associative array  in a library...
Apr 28 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Welcome.

MLT:
 D is really an amazing language!<
Yep.
It really is everything that C++ did not manage to be, at least as far as my
limited experience with it shows.<
I also hope D will never be lot of the things C++ is, because C++ is too many things :-)
 1. struct vs. class As far as I understand, these two reserved words, that in
C++ mean very similar things, in D are very different.<
C++ classes are like structs, but their methods are private by default. In D structs have value semantics, are copied by value and keep the given order of the fields, while classes have reference semantics, are often allocated on the heap, and the compiler in theory can change the order of fields in memory. They are designed for different purposes, and I agree with such decision by But later practice has shown that you want struct constructors, and other things, so now D2 has them too. So structs are a bit closer to classes now in D2.
A class variable is "really" a pointer, whereas a struct is directly allocated
memory.<
A class is a "reference". There are some ways manual or automatic with "scope" to sometimes allocate classes on the stack to improve performance. I have seen that sometimes it gives a nice speedup. You can't create an array of scoped classes by normal means, you have to manually change the way they allocate memory. Generally you can do what you want, but you may need some work to do special kinds of memory allocation.
What I don't like is that it seems that structs and classes should almost be
interchangeable - one might implement something as a class and later want it to
be a struct, or vice versa. It almost is actually a local decision. I might
want something to be a class in one place, and a struct in another.<
In D they are by design different, because most of the times you want just one of the meanings.
It seems to me that these are 3 different issues, and one should have control
over them separately.<
Giving control over each thing is of course nice and it may even increase performance in special situations. But it surely leads to an increase of the complexity of the language (and its use). D tries to be less complex than C++ (and C++ today is probably one of the most complex languages, and such very high complexity is now slowly killing it), and this means that sometimes you have to give up on some flexibility. If the language is well designed then most of the times, in practical programs, you don't feel much of such limitations.
Otherwise, it seems to me that a program that uses both (struct and class) can
get mightily confusing.<
It's confusing if you are used to program in a language like Python, where everything acts according to a reference semantics (more or less, it's not exactly like that, it's a name-semantics). But D is more complex and powerful than Python, and lower level too, and it gives you both reference and data semantics. Once you know that, you just have to keep in memory that classes are by reference and structs are by values, and you can live well (you can also have pointer to structs. I think I have never used a pointer to class in D yet).
 Maybe the solution is to not use struct (which is I guess what is recommended
unless you really need it.)<
Structs are useful in D because classes have some overhead in both memory, and their methods are always virtual (and all the current D compilers are unable to devirtualize such methods, maybe not even GDC is able to do it, even if G++ is sometime able to devirtualize C++ virtual methods, I think it's the only C++ compiler able to do that)), and being usually allocated on the heap (D compilers aren't like HotSpot that is sometimes able to allocate classes on the stack when it is sure they not exit the scope) they aren't fit if you for example need small [x,y] vectors.
 2. char[] vs. int[]
 I think it is strange that 
 char[] x = "1234" ;
 x[0] = '4' ;
 
 Produces a run time error, but
 int[] x = [1,2,3,4] ;
 x[0] = 4 ;
 Doesn't. I think that they both should, or both shouldn't - to be consistent
(and it would be better if they both didn't).
I leave this to other people. in D2 strings are immutable, by the way, while static arrays are not.
Best would be again, to allow the programmer to specify where the array (or
other stuff) should be stored.<
That requires you to pay some complexity. And D designers/programmers may be unwilling to pay it.
Given that, it is even sadder than it is in C++, that one can not inherit from
the basic types.<
Yes, this is a problem of D2. Scala language shows that there are better ways to design types, as you say. Walter has recently changed the D2 language to allow a bit of this, using "this". With that you can define a struct that behaves for example like the built-in associative array, and you don't need to redefine all its almost-methods. Bye, bearophile
Apr 28 2009
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 28 Apr 2009 13:00:36 -0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 MLT:
 2. char[] vs. int[]
 I think it is strange that
 char[] x = "1234" ;
 x[0] = '4' ;

 Produces a run time error, but
 int[] x = [1,2,3,4] ;
 x[0] = 4 ;
 Doesn't. I think that they both should, or both shouldn't - to be  
 consistent (and it would be better if they both didn't).
I leave this to other people. in D2 strings are immutable, by the way, while static arrays are not.
This has been discussed. Most people agree that the behavior should be consistent. Any array literal should be exactly that -- an unchangable literal. In D2, it should be an immutable literal (and produce a compile time error if you try and change it). BTW, this behavior you noticed is only on certain OSes. On other OSes (I think windows), you get weird behavior: char[] x = "1234"; x[0] = '4'; // no runtime error char[] y = "1234"; // y actually now equals "4234"! -Steve
Apr 28 2009
parent MLT <none anon.com> writes:
Steven Schveighoffer Wrote:

 BTW, this behavior you noticed is only on certain OSes.  On other OSes (I  
 think windows), you get weird behavior:
 
 char[] x = "1234";
 x[0] = '4'; // no runtime error
 char[] y = "1234"; // y actually now equals "4234"!
 
 -Steve
Pretty nice. It would be even nicer if you had the following: char[] x = "1234"; x[0] = '4'; // no runtime error char[] y = "12"; // y now equals "42" ;)
Apr 28 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
bearophile wrote:
 Yes, this is a problem of D2. Scala language shows that there are
 better ways to design types, as you say.
Could you please give a little more detail? And speaking of Scala, after having watched a presentation, I was left with the impression that traits are nothing but classes with parameterized base. I mean this: abstract class Person { def schedule:Schedule } trait Student extends Person { private var classSchedule:Schedule = ... override def schedule = classSchedule def learn() = {...} } trait Worker extends Person { private var workSchedule:Schedule = ... override def schedule = workSchedule def work() = {...} } class CollegeStudent(school:School, company:Company) extends Student with Worker { // ... } is really this (in Scala-D made-up language): abstract class Person { def schedule:Schedule } class Student(Base) extends Person { private var classSchedule:Schedule = ... override def schedule = classSchedule def learn() = {...} } class Worker(Base) extends Person { private var workSchedule:Schedule = ... override def schedule = workSchedule def work() = {...} } class CollegeStudent(school:School, company:Company) extends Worker!(Student!(CollegeStudent)) { // ... } Is that correct? Andrei
Apr 28 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 Could you please give a little more detail?
My experience with Scala is near zero, I have written and compiled only small programs, like the ones from the Shootout and the ones of the first tutorial. Scala isn't a language as simple as they say, its type system is quite complex and powerful, so Scala isn't easy to learn if you want to use it well. You can use monads in Scala too, in a decent enough way: http://www.scala-lang.org/node/46 To give you a small answer, in Scala all types are used in a quite uniform way. This is useful. Even integers have a methods (as in Ruby, but Scala is statically compiled). You can add "methods" to all integers: object extendBuiltins extends Application { def fact(n: Int): BigInt = if (n == 0) 1 else fact(n-1) * n class Factorizer(n: Int) { def ! = fact(n) } implicit def int2fact(n: Int) = new Factorizer(n) println(10!) } Removing most of the distinction from built-in types and values and user-defined ones has some advantages. alias this of D2 is a little step in that direction. Like the idea of having first-class types. Once you have first-class types, with run-time-function-evaluation you may not need templates anymore. You have just functions that act on types that run at runtime too. The space of all possible computer languages is huge.
 And speaking of Scala, after having watched a presentation, I was left 
 with the impression that traits are nothing but classes with 
 parameterized base.
[...]
 Is that correct?
I don't know, I am sorry. I may be able to answer your question after reading the Scala docs, but you may do that yourself, and probably more efficiently, because you are smarter. Bye, bearophile
Apr 28 2009
prev sibling next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Tue, Apr 28, 2009 at 12:07 PM, MLT <none anon.com> wrote:

 What I don't like is that it seems that structs and classes should almost=
be interchangeable - one might implement something as a class and later wa= nt it to be a struct, or vice versa. It almost is actually a local decision= . I might want something to be a class in one place, and a struct in anothe= r. I hear this all the time from C++ users. But in practice, it virtually never comes up. I have never, in my five years of using D, wanted to change a class to a struct or vice versa, or ever seen anyone else doing that (or complaining about its difficulty). The only people who complain are those who don't use the language ;)
 And, it seems that struct and class refer to several different things: (1=
) struct and class are allocated in different places, (2) struct is suppose= d to ensure its structure, and (3) struct is copied by value, whereas class= by reference.
 It seems to me that these are 3 different issues, and one should have con=
trol over them separately. Again, in practice, you will virtually always want *either* value semantics *or* polymorphism. In the few cases where you need both, you can imitate it with mixins and the like (and with D2, 'alias this' is nice).
 I find this example a bit strange:
 struct S { int x;}
 class C {int x;}
 void main() {
 {
 =A0S x ;
 =A0x.x =3D 1 ;
 =A0S y =3D x ;
 =A0y.x =3D2 ;
 =A0writefln(x.x) ; // x.x is 1
 }
 {
 =A0C x =3D new C ;
 =A0x.x =3D 1;
 =A0C y =3D x ;
 =A0y.x =3D 2 ;
 =A0writefln(x.x) ; // x.x is 2
 }
 }

 I would have preferred to declare directly that the variable y takes or d=
oesn't take a reference when assigned. Otherwise, it seems to me that a pro= gram that uses both (struct and class) can get mightily confusing. Again, in practice, it doesn't :) You always use some types as values and others always as references. Are C programs that use both ints and char* s mighty confusing?
 Maybe the solution is to not use struct (which is I guess what is recomme=
nded unless you really need it.) Please don't make everything a class. This isn't Java ;) What is instead recommended is that you use structs for value types and classes for everything else.
Apr 28 2009
parent reply grauzone <none example.net> writes:
Jarrett Billingsley wrote:
 On Tue, Apr 28, 2009 at 12:07 PM, MLT <none anon.com> wrote:
 
 What I don't like is that it seems that structs and classes should almost be
interchangeable - one might implement something as a class and later want it to
be a struct, or vice versa. It almost is actually a local decision. I might
want something to be a class in one place, and a struct in another.
I hear this all the time from C++ users. But in practice, it virtually never comes up. I have never, in my five years of using D, wanted to change a class to a struct or vice versa, or ever seen anyone else doing that (or complaining about its difficulty). The only people who complain are those who don't use the language ;)
Often I'd wish to statically allocate an object in the current context, like you can do with a struct. scope partially gives me what I want. It would be nice if "scope" could be used in other places: class Bla { int member; } class Foo { scope Bla b; //object constructed here } static assert(Foo.classinfo.init.size == 5*4); Yeah, you'd need a solution for how to call the ctor. Maybe the (very annoying) way of how initialization of final/const members is handled would be useful here.
Apr 28 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 28 Apr 2009 21:42:51 +0400, grauzone <none example.net> wrote:

 Jarrett Billingsley wrote:
 On Tue, Apr 28, 2009 at 12:07 PM, MLT <none anon.com> wrote:

 What I don't like is that it seems that structs and classes should  
 almost be interchangeable - one might implement something as a class  
 and later want it to be a struct, or vice versa. It almost is actually  
 a local decision. I might want something to be a class in one place,  
 and a struct in another.
I hear this all the time from C++ users. But in practice, it virtually never comes up. I have never, in my five years of using D, wanted to change a class to a struct or vice versa, or ever seen anyone else doing that (or complaining about its difficulty). The only people who complain are those who don't use the language ;)
Often I'd wish to statically allocate an object in the current context, like you can do with a struct. scope partially gives me what I want. It would be nice if "scope" could be used in other places: class Bla { int member; } class Foo { scope Bla b; //object constructed here } static assert(Foo.classinfo.init.size == 5*4); Yeah, you'd need a solution for how to call the ctor. Maybe the (very annoying) way of how initialization of final/const members is handled would be useful here.
I belive it could be implemented as a library type, using Scope(T) template: class Foo { Scope!(Bar) _bar; } Perphaps, Phobos could provide that functionality, then we could deprecate "scope Foo foo = new Foo(args);" in favor of "auto foo = Scope!(Foo)(args);" and eventually remove from language.
Apr 28 2009
parent reply grauzone <none example.net> writes:
 I belive it could be implemented as a library type, using Scope(T) template:
I don't like that approach to replace random language features by templates at all. And in this case, you really have to ask WHY? It's nice that it's possible, but there are some reasons that speak against this approach: 1. it's harder to understand in general (even if the language definition becomes smaller) 2. error messages turn into an incomprehensible mess 3. puts more stress on the compiler and it gets slower (you will understand when you have to _wait_ for your project to finish compilation, even if you use the superfast dmd)
 class Foo
 {
     Scope!(Bar) _bar;
 }
Would typeof(_bar) == Bar?
 Perphaps, Phobos could provide that functionality, then we could deprecate
"scope Foo foo = new Foo(args);" in favor of "auto foo = Scope!(Foo)(args);"
and eventually remove from language.
Apr 28 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 28 Apr 2009 22:50:28 +0400, grauzone <none example.net> wrote:

 I belive it could be implemented as a library type, using Scope(T)  
 template:
I don't like that approach to replace random language features by templates at all. And in this case, you really have to ask WHY? It's nice that it's possible, but there are some reasons that speak against this approach: 1. it's harder to understand in general (even if the language definition becomes smaller) 2. error messages turn into an incomprehensible mess 3. puts more stress on the compiler and it gets slower (you will understand when you have to _wait_ for your project to finish compilation, even if you use the superfast dmd)
 class Foo
 {
     Scope!(Bar) _bar;
 }
Would typeof(_bar) == Bar?
No way! But Scope!(Bar) would be implicitly castable to Bar (just not vice-versa): Bar b = _bar; // allowed _bar = b; // disallowed In fact, I don't like scope as it is: scope Foo foo = ...; // is foo scope allocated or not? It depends: scope Foo foo = new Foo(); // scope-allocated Foo getFoo() { return new Foo(); } scope Foo foo = getFoo(); // ???? In last example, DMD may inline and make it scope-allocated, but may not inline and make it heap-allocated. Scope!(Foo) foo = ...; gives you better control over allocation. For example, Scope!(Foo) foo = getFoo(); won't even compile.
Apr 28 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Denis Koroskin wrote:
 ...
Scope stack-allocating is an optimisation. It doesn't guarantee it because that it's the point of scope. Given that you're hung-up about stack allocation, I can't imagine how you'd implement scope as a template. Hell, I can't imagine how you'd implement Scope as a template for *any* of its behaviours. class Foo { Scope!(Bar) _bar; } How do you guarantee deterministic destruction when it's inside a non-deterministic construct? -- Daniel
Apr 28 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 29 Apr 2009 06:09:49 +0400, Daniel Keep <daniel.keep.lists gmail.com>
wrote:

 Denis Koroskin wrote:
 ...
Scope stack-allocating is an optimisation. It doesn't guarantee it because that it's the point of scope. Given that you're hung-up about stack allocation, I can't imagine how you'd implement scope as a template. Hell, I can't imagine how you'd implement Scope as a template for *any* of its behaviours. class Foo { Scope!(Bar) _bar; } How do you guarantee deterministic destruction when it's inside a non-deterministic construct? -- Daniel
Is that a challenge? import std.stdio; class Foo { this(int i, int j, int k) { writeln("Foo.this(): ", i, j, k); } ~this() { writeln("Foo.~this()"); } } struct Scope(T) { this(Args...)(Args args) { _data[] = T.classinfo.init[]; // shouldn't be needed __get.__ctor(args); } ~this() { __get.__dtor(); } alias __get this; T __get() { return cast(T)_data.ptr; } static assert(is(T == class)); private byte[__traits(classInstanceSize, T)] _data; //private byte[__traits(classInstanceSize, T)] _data = T.classinfo.init; // bug: doesn't work } void main() { auto foo = Scope!(Foo)(1, 2, 3); } One more bug-o-feature is that Scope.ctor is not called when args set is empty: auto foo = Scope!(Foo)(); // no Scope.__ctor is called and thus underlying Foo instance is left uninitialized. I never understood a rationale behind this "feature". I believe it's a hole.
Apr 29 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
Here is another example:

import std.stdio;
import Scope;

class Foo
{
    this(int i, int j, int k) {
        writeln("Foo.this(): ", i, j, k);
    }
    
    ~this() {
        writeln("Foo.~this()");
    }
}

class Bar
{
    this(int i, int j, int k)
    {
        writeln("Bar.this(): ", i, j, k);
        foo = Scope!(Foo)(i, j, k);
    }
    
    ~this()
    {
        writeln("Bar.~this()");
    }

    Scope!(Foo) foo;
}

// Just for comparison - note that they are almost the same
class NoScopeBar
{
    this(int i, int j, int k)
    {
        writeln("NoScopeBar.this()");
        foo = new Foo(i, j, k);
    }

    ~this()
    {
        writeln("NoScopeBar.~this()");
    }

    Foo foo;
}

void main()
{
    auto bar = Scope!(Bar)(1, 2, 3);
}

Expected output:

Bar.this(): 123
Foo.this(): 123
Bar.~this()
Foo.~this()

Output:
Bar.this(): 123
Foo.this(): 123
Bar.~this()

It is a DMD bug: calling an object's dtor should call dtors on all its fields.
Apr 29 2009
parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 29 Apr 2009 13:06:18 +0400, Denis Koroskin <2korden gmail.com> wrote:

 It is a DMD bug: calling an object's dtor should call dtors on all its  
 fields.
This could be temporarily worked around by little template magic: foreach(field; filterFields(__traits(allMembers,T))) { field.dtor(); }
Apr 29 2009
prev sibling parent reply Tomas Lindquist Olsen <tomas.l.olsen gmail.com> writes:
On Tue, Apr 28, 2009 at 6:07 PM, MLT <none anon.com> wrote:
 2. char[] vs. int[]
 I think it is strange that
 char[] x = "1234" ;
 x[0] = '4' ;

 Produces a run time error, but
 int[] x = [1,2,3,4] ;
 x[0] = 4 ;
 Doesn't. I think that they both should, or both shouldn't - to be consistent
(and it would be better if they both didn't). Best would be again, to allow the
programmer to specify where the array (or other stuff) should be stored.
It pretty much boils down to this (mostly said in other replies) * string literals are special, they are allocated in a static data segment, readonly if the platform allows it. * arrayliterals as non-static expressions are always heap allocated. even when there's absolute no need for it... (see http://d.puremagic.com/issues/show_bug.cgi?id=2356 ) -Tomas
Apr 28 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 28 Apr 2009 22:13:50 +0400, Tomas Lindquist Olsen
<tomas.l.olsen gmail.com> wrote:

 On Tue, Apr 28, 2009 at 6:07 PM, MLT <none anon.com> wrote:
 2. char[] vs. int[]
 I think it is strange that
 char[] x = "1234" ;
 x[0] = '4' ;

 Produces a run time error, but
 int[] x = [1,2,3,4] ;
 x[0] = 4 ;
 Doesn't. I think that they both should, or both shouldn't - to be  
 consistent (and it would be better if they both didn't). Best would be  
 again, to allow the programmer to specify where the array (or other  
 stuff) should be stored.
It pretty much boils down to this (mostly said in other replies) * string literals are special, they are allocated in a static data segment, readonly if the platform allows it. * arrayliterals as non-static expressions are always heap allocated. even when there's absolute no need for it... (see http://d.puremagic.com/issues/show_bug.cgi?id=2356 ) -Tomas
Someone ought to post a feature request to make arrayliterals immutable by default (D2 only, I don't think this change will go to D1 anyway) and don't heap-allocate them every time they're used: int[] x1 = [1,2,3,4]; // error: can't assign immutable(int)[] to int[] int[] x2 = [1,2,3,4].dup; // okay, allocates int[4] x3 = [1,2,3,4]; // okay, doesn't allocate foreach (int i; [1,2,3,4]) { // okay, doesn't allocate // ... }
Apr 28 2009
parent reply grauzone <none example.net> writes:
Denis Koroskin wrote:
 On Tue, 28 Apr 2009 22:13:50 +0400, Tomas Lindquist Olsen
<tomas.l.olsen gmail.com> wrote:
 
 On Tue, Apr 28, 2009 at 6:07 PM, MLT <none anon.com> wrote:
 2. char[] vs. int[]
 I think it is strange that
 char[] x = "1234" ;
 x[0] = '4' ;

 Produces a run time error, but
 int[] x = [1,2,3,4] ;
 x[0] = 4 ;
 Doesn't. I think that they both should, or both shouldn't - to be  
 consistent (and it would be better if they both didn't). Best would be  
 again, to allow the programmer to specify where the array (or other  
 stuff) should be stored.
It pretty much boils down to this (mostly said in other replies) * string literals are special, they are allocated in a static data segment, readonly if the platform allows it. * arrayliterals as non-static expressions are always heap allocated. even when there's absolute no need for it... (see http://d.puremagic.com/issues/show_bug.cgi?id=2356 ) -Tomas
Someone ought to post a feature request to make arrayliterals immutable by default (D2 only, I don't think this change will go to D1 anyway) and don't heap-allocate them every time they're used: int[] x1 = [1,2,3,4]; // error: can't assign immutable(int)[] to int[]
Why not auto-allocate? Writing that .dup all the time is going to be annoying. Just implicitly convert it from immutable to mutable by copying.
 int[] x2 = [1,2,3,4].dup; // okay, allocates
 
 int[4] x3 = [1,2,3,4]; // okay, doesn't allocate
 
 foreach (int i; [1,2,3,4]) { // okay, doesn't allocate
     // ...
 }
Apr 28 2009
parent reply Don <nospam nospam.com> writes:
grauzone wrote:
 Denis Koroskin wrote:
 On Tue, 28 Apr 2009 22:13:50 +0400, Tomas Lindquist Olsen 
 <tomas.l.olsen gmail.com> wrote:

 On Tue, Apr 28, 2009 at 6:07 PM, MLT <none anon.com> wrote:
 2. char[] vs. int[]
 I think it is strange that
 char[] x = "1234" ;
 x[0] = '4' ;

 Produces a run time error, but
 int[] x = [1,2,3,4] ;
 x[0] = 4 ;
 Doesn't. I think that they both should, or both shouldn't - to be  
 consistent (and it would be better if they both didn't). Best would 
 be  again, to allow the programmer to specify where the array (or 
 other  stuff) should be stored.
It pretty much boils down to this (mostly said in other replies) * string literals are special, they are allocated in a static data segment, readonly if the platform allows it. * arrayliterals as non-static expressions are always heap allocated. even when there's absolute no need for it... (see http://d.puremagic.com/issues/show_bug.cgi?id=2356 ) -Tomas
Someone ought to post a feature request to make arrayliterals immutable by default (D2 only, I don't think this change will go to D1 anyway) and don't heap-allocate them every time they're used:
Definitely. They should go into the initialized data segment.
 int[] x1 = [1,2,3,4]; // error: can't assign immutable(int)[] to int[]
Why not auto-allocate? Writing that .dup all the time is going to be annoying. Just implicitly convert it from immutable to mutable by copying.
I think it's pretty unlikely that you'd want to do that. It's far more likely that it's a bug, and you meant it to be an immutable(int)[]. Except in the case where the array is empty. (Likewise, it'd be nice if char [] s=""; were legal in D2. Since a mutable "" string has nothing that can be changed anyway, "" can be treated in the same way that 'null' is).
 
 int[] x2 = [1,2,3,4].dup; // okay, allocates

 int[4] x3 = [1,2,3,4]; // okay, doesn't allocate

 foreach (int i; [1,2,3,4]) { // okay, doesn't allocate
     // ...
 }
Apr 29 2009
next sibling parent Georg Wrede <georg.wrede iki.fi> writes:
Don wrote:
 (Likewise, it'd be nice if char [] s=""; were legal in D2. Since a 
 mutable "" string has nothing that can be changed anyway, "" can be 
 treated in the same way that 'null' is).
There was a huge discussion about null strings a few years ago. (Probably it was before Andrei, and possibly before your time.) IIRC, most of the discussion was about detecting the "nullness" of a string, and what we should define the Null string to be, there were a few good thoughts around the subject in general.
Apr 29 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 29 Apr 2009 05:44:07 -0400, Don <nospam nospam.com> wrote:


 Except in the case where the array is empty.
 (Likewise, it'd be nice if char [] s=""; were legal in D2. Since a  
 mutable "" string has nothing that can be changed anyway, "" can be  
 treated in the same way that 'null' is).
Why is this more desirable than just: char[] s; int[] i; Which works now. -Steve
Apr 29 2009