www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Other language features you'd want in D

reply Denton Cockburn <diboss hotmail.com> writes:
What are some features found in other languages that you believe would be
really good to have in D?

These can be language features or library features.

It shouldn't be any of the general items found in the comparison FAQ (like
Multiple inheritance).  Something that's relatively nice and specific.

e.g.
I miss multiple value returns found in Lisp.  Out parameters are not
nearly as nice.

P.S. Has anyone thought to write a document on some of the struct tricks
that I've been seeing mentioned?  They exploit struct features, but I
think only a select few understand them.
Feb 22 2008
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Denton Cockburn wrote:
 What are some features found in other languages that you believe would be
 really good to have in D?
 
 These can be language features or library features.
 
 It shouldn't be any of the general items found in the comparison FAQ (like
 Multiple inheritance).  Something that's relatively nice and specific.
 
 e.g.
 I miss multiple value returns found in Lisp.  Out parameters are not
 nearly as nice.
 
 P.S. Has anyone thought to write a document on some of the struct tricks
 that I've been seeing mentioned?  They exploit struct features, but I
 think only a select few understand them.

Initializing runtime constants without a static this() a la Java, class C { static int x = someRuntimeInitializer(10); int y = someRuntimeInitializer(20); }
Feb 22 2008
parent reply Denton Cockburn <diboss hotmail.com> writes:
On Fri, 22 Feb 2008 15:25:24 -0800, Robert Fraser wrote:

 Denton Cockburn wrote:
 What are some features found in other languages that you believe would be
 really good to have in D?
 
 These can be language features or library features.
 
 It shouldn't be any of the general items found in the comparison FAQ (like
 Multiple inheritance).  Something that's relatively nice and specific.
 
 e.g.
 I miss multiple value returns found in Lisp.  Out parameters are not
 nearly as nice.
 
 P.S. Has anyone thought to write a document on some of the struct tricks
 that I've been seeing mentioned?  They exploit struct features, but I
 think only a select few understand them.

Initializing runtime constants without a static this() a la Java, class C { static int x = someRuntimeInitializer(10); int y = someRuntimeInitializer(20); }

I don't mind the static this() thing much. It puts all the initialization in one place. I hated having to read this in java: class Foo { /* variables with inits */ /* some functions */ /* some variables with inits that were added to the class later */ } I will admit that it's quite a bit more typing though, especially with many defaulted variables.
Feb 22 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Denton Cockburn wrote:
 On Fri, 22 Feb 2008 15:25:24 -0800, Robert Fraser wrote:
 
 Denton Cockburn wrote:
 What are some features found in other languages that you believe would be
 really good to have in D?

 These can be language features or library features.

 It shouldn't be any of the general items found in the comparison FAQ (like
 Multiple inheritance).  Something that's relatively nice and specific.

 e.g.
 I miss multiple value returns found in Lisp.  Out parameters are not
 nearly as nice.

 P.S. Has anyone thought to write a document on some of the struct tricks
 that I've been seeing mentioned?  They exploit struct features, but I
 think only a select few understand them.

class C { static int x = someRuntimeInitializer(10); int y = someRuntimeInitializer(20); }

I don't mind the static this() thing much. It puts all the initialization in one place. I hated having to read this in java: class Foo { /* variables with inits */ /* some functions */ /* some variables with inits that were added to the class later */ } I will admit that it's quite a bit more typing though, especially with many defaulted variables.

Constant initialization can already be paired with declaration for non-class types: const(int) HTTP_PORT = 80; But it can't be for class types at global scope: const(Port) HTTP_PORT = new Port(80); How is making it valid for (primitives, arrays, structs, anything with a constant initializer) but not for classes "keeping initialization in one place"?
Feb 23 2008
next sibling parent Denton Cockburn <diboss hotmail.com> writes:
On Sat, 23 Feb 2008 03:13:45 -0800, Robert Fraser wrote:

 Denton Cockburn wrote:
 On Fri, 22 Feb 2008 15:25:24 -0800, Robert Fraser wrote:
 
 Denton Cockburn wrote:
 What are some features found in other languages that you believe would be
 really good to have in D?

 These can be language features or library features.

 It shouldn't be any of the general items found in the comparison FAQ (like
 Multiple inheritance).  Something that's relatively nice and specific.

 e.g.
 I miss multiple value returns found in Lisp.  Out parameters are not
 nearly as nice.

 P.S. Has anyone thought to write a document on some of the struct tricks
 that I've been seeing mentioned?  They exploit struct features, but I
 think only a select few understand them.

class C { static int x = someRuntimeInitializer(10); int y = someRuntimeInitializer(20); }

I don't mind the static this() thing much. It puts all the initialization in one place. I hated having to read this in java: class Foo { /* variables with inits */ /* some functions */ /* some variables with inits that were added to the class later */ } I will admit that it's quite a bit more typing though, especially with many defaulted variables.

Constant initialization can already be paired with declaration for non-class types: const(int) HTTP_PORT = 80; But it can't be for class types at global scope: const(Port) HTTP_PORT = new Port(80); How is making it valid for (primitives, arrays, structs, anything with a constant initializer) but not for classes "keeping initialization in one place"?

I agree. It's also somewhat inconsistent that we can initial these primitives during declaration globally, but yet, it can't be done in classes.
Feb 23 2008
prev sibling parent reply Alexander Panek <alexander.panek brainsware.org> writes:
Robert Fraser wrote:
 Constant initialization can already be paired with declaration for 
 non-class types:
 
 const(int) HTTP_PORT = 80;
 
 But it can't be for class types at global scope:
 
 const(Port) HTTP_PORT = new Port(80);
 
 
 How is making it valid for (primitives, arrays, structs, anything with a 
 constant initializer) but not for classes "keeping initialization in one 
 place"?

You're having a compile-time literal vs. a runtime object here. That's kinda a big difference, you know? I wouldn't want to have my runtime object initialization to be somewhere in class declaration scope. Kinda hard to measure the performance then. Oh, besides... this wouldn't even be in static constructor, but rather the normal constructor. class A { Port httpPort; this (int port = 80) { httpPort = new Port(port); } } I'd like to keep the "verbosity" of initializing class members at runtime as-is.
Feb 23 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Alexander Panek wrote:
 Robert Fraser wrote:
 Constant initialization can already be paired with declaration for 
 non-class types:

 const(int) HTTP_PORT = 80;

 But it can't be for class types at global scope:

 const(Port) HTTP_PORT = new Port(80);


 How is making it valid for (primitives, arrays, structs, anything with 
 a constant initializer) but not for classes "keeping initialization in 
 one place"?

You're having a compile-time literal vs. a runtime object here. That's kinda a big difference, you know? I wouldn't want to have my runtime object initialization to be somewhere in class declaration scope. Kinda hard to measure the performance then. Oh, besides... this wouldn't even be in static constructor, but rather the normal constructor. class A { Port httpPort; this (int port = 80) { httpPort = new Port(port); } } I'd like to keep the "verbosity" of initializing class members at runtime as-is.

You don't need a class for that, as you probably know. What I want is for: const(Port) HTTP_PORT = new Port(80); to be equivalent to: Port HTTP_PORT; static this() { HTTP_PORT = new Port(80); } except, you know, allowing the const in there somewhere.
Feb 23 2008
parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 24 Feb 2008 00:19:59 +0100, Robert Fraser  =

<fraserofthenight gmail.com> wrote:

 Alexander Panek wrote:
 Robert Fraser wrote:
 Constant initialization can already be paired with declaration for  =



 non-class types:

 const(int) HTTP_PORT =3D 80;

 But it can't be for class types at global scope:

 const(Port) HTTP_PORT =3D new Port(80);


 How is making it valid for (primitives, arrays, structs, anything wi=



 a constant initializer) but not for classes "keeping initialization =



 one place"?



 kinda a big difference, you know? I wouldn't want to have my runtime =


 object initialization to be somewhere in class declaration scope. Kin=


 hard to measure the performance then.
  Oh, besides... this wouldn't even be in static constructor, but rath=


 the normal constructor.
  class A {
     Port httpPort;
      this (int port =3D 80) {
         httpPort =3D new Port(port);
     }
 }
  I'd like to keep the "verbosity" of initializing class members at  =


 runtime as-is.

You don't need a class for that, as you probably know. What I want is =

 for:

 const(Port) HTTP_PORT =3D new Port(80);

 to be equivalent to:

 Port HTTP_PORT;
 static this() { HTTP_PORT =3D new Port(80); }

 except, you know, allowing the const in there somewhere.

Something like this was mentioned a few months back. That any compile-ti= me = initialization the compiler wasn't able to do at compile time, should be= = automagically moved to a static this. I don't remember what Walter said = = about it, though. IMO it sounds like a nice feature, but one that should show a warning.
Feb 23 2008
prev sibling next sibling parent reply "dominik" <aha aha.com> writes:
"Denton Cockburn" <diboss hotmail.com> wrote in message 
news:pan.2008.02.22.21.00.40.605571 hotmail.com...
 What are some features found in other languages that you believe would be
 really good to have in D?

Since I'm still learning, I can't say on much more advanced stuff. But, the most problematic aspect of the language I've seen yet (I use D1 still) has got to be array initialization, struct initialization and god-forbid both in the same context. for example, though this might've been solved for D2 already: char[][int] foo = [1:"barbar", 2:"bar"]; - this won't work with dmd compiler, but this will: char[][int] foo = [1:"barbar"[], 2:"bar"]; then, as a newcomer, I seem to never quite understand how shall I initialize my array.. so I got into a habit of instead modeling an array in head like I did with C, I use this little trick with pragma where I actually model data in order to get an array definition out of it: so, for example this little line where it is OBVIOUS to me what I wan't data to be modeled: pragma(msg, typeof([["foo"[]: "bar"[]]: 5]).stringof); gives me: int[char[][char[]]] - which is something rather UGH to model in my mind, since words fail me here :) ok, so I thought to myself, no big deal, right? I'll use .typeof(..).stringof to get the right definition since I'm retarded and can model data immidiately, while I can't seem to model the definition.. nice trick there with that line.. moving on.. AND then.. while working on something I had to make a static struct definitions which consists of its own substructs and arrays of different sorts (I have tried to model my incoming data as precisely as possible to avoid possible translation issues later on). So, first things first - I have tried to write a simple test, and it worked: file: test.d ?? more text below code --- module test; import tango.io.Stdout; align(1) struct DST { private int test; private char[] secondtest; } public static DST[char[]] AA; static this() { AA["Africa/Asmara"] = DST(5, "bla"); AA["Africabambata/Asmara"] = DST(6, "blabla"); } void main() { foreach(v; AA) { Stdout.formatln("{} : {}", v.test, v.secondtest); } Stdout.formatln("{}", AA["Africa/Asmara"].test); Stdout.formatln("{}", AA["Africa/Asmara"].secondtest); } --- sure, confident with this little test, I wrote one with static or dynamic initialization of "pointers" to static data, so it looked like this: file: test2.d ?? more text below code --- module test2; import tango.io.Stdout; struct Foo { int x; char[] y; char[] key; } static Foo[] data = [ {0, "blah", "key1"}, {10, "foo", "key2"} ]; Foo*[char[]] aa; void init() { foreach (inout foo; data) { aa[foo.key] = &foo; } } static this(){ init(); // initialize compile time } void main() { //init(); // initialize run-time foreach(v; aa) { Stdout.formatln("{} - {} - {}", v.x, v.y, v.key); } Stdout.formatln("{}", aa["key2"].x); } --- alrighty then, it works, now onto the real thing - where TROUBLE, for me, starts: first let me post a definition of struct itself: --- struct DST { char[] tz_key; char[] tz_version; char[] timestamp; //-aliases char[] geo_coordinates; //-Annual Transition Policy annualTransitionPolicy[] annualTransitionPolicies; //-Initial Annual Transition Policy initialAnnualTransitionPolicy[] initialAnnualTransitionPolicies; } struct annualTransitionPolicy { intraYearTransition[] intraYearTransitions; endOfYearTransition[] endOfYearTransitions; int effectiveYear; char[] effectiveYearCalendar; char[] effectiveYearRelativity; bool isSymmetric; } struct intraYearTransition { char[] defaultAbbreviation; uint offsetSecondsFromUT; uint stdTimeOffsetSecondsFromUT; char[] relativity; uint transitionSecondsSinceStartOfDay; transitionAnnualDate[] transitionAnnualDates; } struct transitionAnnualDate { char[] calendar; month[] months; ushort minDayOfMonth; dayOfWeek[] dayOfWeeks; ushort daysOffset; } struct month { ushort ordial; } struct dayOfWeek { char[] key; } struct endOfYearTransition { char[] defaultAbbreviation; uint offsetSecondsFromUT; uint stdTimeOffsetSecondsFromUT; } struct initialAnnualTransitionPolicy { endOfYearTransition[] endOfYearTransitions; } --- which in lame-mans graph would look like this (hopefully indentation will be right in NG reader, if not follow this url for this particular paste: http://rafb.net/p/5hcyWq21.html) --- struct DST { char[] tz_key; char[] tz_version; char[] timestamp; char[] geo_coordinates; annualTransitionPolicy[] annualTransitionPolicies; intraYearTransition[] intraYearTransitions; char[] defaultAbbreviation; uint offsetSecondsFromUT; uint stdTimeOffsetSecondsFromUT; char[] relativity; uint transitionSecondsSinceStartOfDay; transitionAnnualDate[] transitionAnnualDates; char[] calendar; month[] months; ushort ordial; ushort minDayOfMonth; dayOfWeek[] dayOfWeeks; char[] key; ushort daysOffset; endOfYearTransition[] endOfYearTransitions; int effectiveYear; char[] effectiveYearCalendar; char[] effectiveYearRelativity; bool isSymmetric; initialAnnualTransitionPolicy[] initialAnnualTransitionPolicies; endOfYearTransition[] endOfYearTransitions; char[] defaultAbbreviation; uint offsetSecondsFromUT; uint stdTimeOffsetSecondsFromUT; } --- and now I have tried to manually initialize static data so I can make a working model in order to feed it to my custom parser/generator for that kind of data (paste if indentation is wrong: http://rafb.net/p/ZhpxOw98.html: --- static DST[] DSTData_build = [ { "bla", "bla", "bla", "bla", //annualTransitionPolicy[] annualTransitionPolicies; {[ //intraYearTransition{} intraYearTransitions; [ "bla", 0, 0, "bla", 0, //transitionAnnualDate{} transitionAnnualDates; [ "bla", //month{} months; [ 0 ], 0, //dayOfWeek{} dayOfWeeks; [ "bla" ], 0 ] ], //endOfYearTransition{} endOfYearTransitions; [ 0, "bla", "bla", true ] ]}, //initialAnnualTransitionPolicy{} initialAnnualTransitionPolicies; {[ //endOfYearTransition{} endOfYearTransitions; [ "bla", 0, 0 ] ]} } ]; --- full source is here: http://rafb.net/p/j33uH170.html so that I don't spam NG with any more of text.. now as you can see, as a newcomer I simply can't get along with this initializer things, particulary arrays and structs - and combinations of both. What I would like to see is some kind of a switch to a compiler or some tool that reads in the definition of a struct like I've shown and generates a dummy initializer upon which I can work with. Since working on this for last couple of days on and off, I still haven't been able to properly initialize my static data, I just can't do it - yes, I may be retarded, I even considered to split out structs and possibly arrays and hash their keys with their parent struct identifier, but data is too complex to be split off in that way for now - and in the end, this SHOULD BE EASY TO DO - all other things in D are easy, even for me, but this is something that needs to be either better explained or reimplemented in a more simpler fashion OR that kind of tool/switch thing that makes a dummy initializer upon which one can work. Thank you and my apologies for a huge rant.
Feb 22 2008
next sibling parent "dominik" <aha aha.com> writes:
I know its not polite to answer my own post, but one more thing - even 
though I use tango from day to day, I applaud bitfields implementation in 
std.. now make them part of the language - certanly most people don't use 
it, but those who do work with them all the time
I know its a fantasy but it would be "cool" - and here I'm just pitching an 
idea - to access bits in a variable in D array fashion for example

classic way:
ubyte x = 14;
ubyte temp = x &0x7; // to access "first" three bits

x:
00001110
temp:
00000110

"new" way of sorts (I haven't gave much thought to syntax, ofcourse - cast 
is foolish, but eh):
ubyte x = 14;
ubyte temp = cast(bitselect)x[$-3..$]; 
Feb 22 2008
prev sibling parent reply downs <default_357-line yahoo.de> writes:
dominik wrote:
 for example, though this might've been solved for D2 already:
 
 char[][int] foo = [1:"barbar", 2:"bar"]; - this won't work with dmd 
 compiler,
 
 but this will:
 
 char[][int] foo = [1:"barbar"[], 2:"bar"];
 

Agreed. Initializers' type deductions should automatically use the most specialized type that can accomodate all the values. Same thing for delegate/function literal return-type deductions. so ["foo", "bar"] should be char[3][2], as currently, but ["foo", "barf"] should use char[][2] automatically, (int i) { if (i) return 2; else return 3f; } should be float delegate(int). That falls under "small stuff that adds to language polish". And language polish, in the long run, is probably more important than groundbreaking features. Please think about it. :) --downs
Feb 28 2008
parent reply bearophile <bearophileHUGS lycos.com> writes:
downs:
 so ["foo", "bar"] should be char[3][2], as currently, but ["foo", "barf"]
should use
 char[][2] automatically,

Too much automatic things may lead to problems. I don't like that too much. I'd like a more systematic (uniform) behavior there (for example: "always create dynamic array when not explicitly specified otherwise"). Bye, bearophile
Feb 28 2008
parent =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
On Thu, 28 Feb 2008, bearophile wrote:

 downs:
 so ["foo", "bar"] should be char[3][2], as currently, but ["foo", "barf"]
should use
 char[][2] automatically,

Too much automatic things may lead to problems. I don't like that too much. I'd like a more systematic (uniform) behavior there (for example: "always create dynamic array when not explicitly specified otherwise").

Having the most general case as default is easier to remember. But if one writes: char[3][2] foo = [ "foo", "bar" ]; it should still be able to unify the types. Having the opposite as default is annoying since it can lead to subtle bugs. I once had an array of strings that worked just fine with Stdout() (in tango), but FilePath couldn't find the file. Even strace couldn't reveal the bug. But adding missing []s fixed it.
 Bye,
 bearophile

Feb 28 2008
prev sibling parent reply Clay Smith <clayasaurus gmail.com> writes:
Denton Cockburn wrote:
 What are some features found in other languages that you believe would be
 really good to have in D?
 
 These can be language features or library features.
 
 It shouldn't be any of the general items found in the comparison FAQ (like
 Multiple inheritance).  Something that's relatively nice and specific.
 
 e.g.
 I miss multiple value returns found in Lisp.  Out parameters are not
 nearly as nice.
 
 P.S. Has anyone thought to write a document on some of the struct tricks
 that I've been seeing mentioned?  They exploit struct features, but I
 think only a select few understand them.

For me, I feel that D 2.0 or 3.0 will become a dreaded kitchen sink of features. Rather, I like to think about what features should be kept out of the language. I appreciate language elegance and simplicity because it helps create more maintainable code, and as one of D's original goals, it helps make writing a compiler easier. However, with D 2.0 etc. writing a D compiler is no longer an easy task. Probably still easier than C++, but C++ is a freak hybrid language. I don't really care about super-meta-macro-templates or constness... although there does seem to be an elite few who love abusing the compiler and that's pretty amusing to see their codes... at least /me thinks of Tom S. ;0
Feb 22 2008
parent bearophile <bearophileHUGS lycos.com> writes:
Clay Smith:
 For me, I feel that D 2.0 or 3.0 will become a dreaded kitchen sink of
features.

Many features add complexity to a language (or to a system), but that's not the main problem. The main source of complexity is the strange interactions between features. When they keep being orthogonal they don't add too much complexity. Many features of C++ interact in messy ways, and they have exceptions, and exceptions to exceptions. That's the recipe to quickly increase the complexity. If you want D to keep having low complexity, you have to clean (and debug) the interaction between features. At the moment D has various things that are less clean than possible, so it can be improved there... Bye, bearophile
Feb 23 2008