www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - string initialization question.

reply dcoder <dcoder devnull.com> writes:
Hello.

Is there anyway in D to convenient fill a string variable with a char say X
times?

So, I'd like to do something like:

string divider( size, '-');    // C++ notation.
$divider = '-' x $size;        // perl notation.


I thought I could do the following:

const char divider[rowstr.length] = '-';

but the compiler complains about not having a constant integer expression.

thanks.
Jul 30 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 30 Jul 2010 11:24:41 -0400, dcoder <dcoder devnull.com> wrote:

 Hello.

 Is there anyway in D to convenient fill a string variable with a char  
 say X times?

 So, I'd like to do something like:

 string divider( size, '-');    // C++ notation.
 $divider = '-' x $size;        // perl notation.


 I thought I could do the following:

 const char divider[rowstr.length] = '-';

 but the compiler complains about not having a constant integer  
 expression.

 thanks.

It's most likely complaining about rowstr.length not being a constant, not the '-'. This works: const char divider[5] = '-'; If you want to allocate a new array on the heap with '-' in it, I think there is a way, but I'm not sure how to do it. I'm pretty sure there's a runtime function to do it. -Steve
Jul 30 2010
parent reply Justin Spahr-Summers <Justin.SpahrSummers gmail.com> writes:
On Fri, 30 Jul 2010 11:35:15 -0400, Steven Schveighoffer 
<schveiguy yahoo.com> wrote:
 
 On Fri, 30 Jul 2010 11:24:41 -0400, dcoder <dcoder devnull.com> wrote:
 
 Hello.

 Is there anyway in D to convenient fill a string variable with a char  
 say X times?

 So, I'd like to do something like:

 string divider( size, '-');    // C++ notation.
 $divider = '-' x $size;        // perl notation.


 I thought I could do the following:

 const char divider[rowstr.length] = '-';

 but the compiler complains about not having a constant integer  
 expression.

 thanks.

It's most likely complaining about rowstr.length not being a constant, not the '-'. This works: const char divider[5] = '-'; If you want to allocate a new array on the heap with '-' in it, I think there is a way, but I'm not sure how to do it. I'm pretty sure there's a runtime function to do it. -Steve

Something like this will work on the heap: char[] divider = new char[5]; divider[] = '-';
Jul 30 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:
     char[] divider = new char[5];
     divider[] = '-';

That assigns 0xff to all divider chars, and then assigns '-'. I think there's a way to do it without the initial assignment.

In past there was some way to do that: typedef char mchar = '-'; mchar[] divider = new mchar[5]; Now you have to initialize the dynamic array two times (using a char struct with alias this is probably not a good idea). I have shown this problem, but I think Walter was not interested. Maybe LDC will able to optimize away the first initialization, I have an enhancement request for LLVM. Bye, bearophile
Jul 30 2010
next sibling parent reply Jonathan M Davis <jmdavisprog gmail.com> writes:
On Friday, July 30, 2010 10:14:45 Steven Schveighoffer wrote:
 I think a function to do it is fine, like makeArray('-', 5);

Well, creating a function for producing an array literal and returning it using templates and string mixins wouldn't be all that hard, but if you want to create a dynamic array of arbitrary size at runtime, that's not going to work, and a makeArray() function would have exactly the same tools that you have to create an array of all the same value. So, it's not going to be any more efficient that what you can do. int[] a = new int[](x); a[] = val; _should_ be fairly easily optimized by the compiler and thus really should be optimized down to an initialization rather than an initialization and an assignment. A makeArray() function wouldn't hurt any, but I don't think that it would really buy us much. Of course, truth be told, I've always thought that the ability to construct a string or vector in C++ all of a single value was pretty useless. Obviously, some people find it useful at least once in a while, but I've never had much use for it. A makeArray() function would probably still be a good thing to have, but what we really need here is either a syntactic way to do it or for the compiler to optimize out the useless initialization (as well as inline makeArray()) so that you don't have to deal with the extra cost of setting everything twice. - Jonathan M Davis
Jul 30 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:
 a makeArray() function would have exactly the same tools that you have to
create 
 an array of all the same value. So, it's not going to be any more efficient
that 
 what you can do.

Doesn't the D2 GC give you a lower level function to GC-allocate uninitialized memory? The GC in D1 has such function, so in D1 it's easy to create a makeArray(). Bye, bearophile
Jul 30 2010
prev sibling parent reply dcoder <blah blah.com> writes:
== Quote from Jonathan M Davis (jmdavisprog gmail.com)'s article
 A makeArray() function wouldn't hurt any, but I don't think that it would
really
 buy us much. Of course, truth be told, I've always thought that the ability to
 construct a string or vector in C++ all of a single value was pretty useless.
 Obviously, some people find it useful at least once in a while, but I've never
 had much use for it. A makeArray() function would probably still be a good
thing
 to have, but what we really need here is either a syntactic way to do it or for
 the compiler to optimize out the useless initialization (as well as inline
 makeArray()) so that you don't have to deal with the extra cost of setting
 everything twice.
 - Jonathan M Davis

If I'm writing a program that pretty prints tree data, or output of sql, like Oracle's sqlplus, or postgres equivalent, I find having such a utility function/constructor a pretty handy feature. I don't know where such a tool should finally be placed in D, but I having it available as a library or as part of the language would be great. It seems like a lot of other languages have it like python, perl, C++, and Java. So it can't be that useless.
Jul 30 2010
parent Justin Spahr-Summers <Justin.SpahrSummers gmail.com> writes:
On Fri, 30 Jul 2010 16:30:17 -0700, Jonathan M Davis 
<jmdavisprog gmail.com> wrote:
 On Friday, July 30, 2010 14:13:15 dcoder wrote:
 If I'm writing a program that pretty prints tree data, or output of sql,
 like Oracle's sqlplus, or postgres equivalent, I find having such a
 utility function/constructor a pretty handy feature.
 
 I don't know where such a tool should finally be placed in D, but I having
 it available as a library or as part of the language would be great.  It
 seems like a lot of other languages have it like python, perl, C++, and
 Java.  So it can't be that useless.

Well, I certainly have no problem with a function like makeArray() existing. It's just that it's one of those functions that I've never found useful, and I don't think that I've ever seen anyone use it in code.

I agree with this sentiment. I think the feature is pretty niche to begin with, and the compiler should be able to optimize out the initialization in the sample I gave previously. D is indeed a systems language, but I (and I'm sure others) would like to use it in a high- level way, where I can write natural, straightforward code and expect the compiler to do the Right Thing. Besides, performance is not an applicable argument for this use case. Even if the array initialization is compiled into the binary, the amount of time it would take is infinitesimal. If someone's trying to initialize a 100,000 element array to some specific value, they're likely going to write their own makeArray() anyways.
Jul 30 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 30 Jul 2010 15:56:36 -0400, Jonathan M Davis  
<jmdavisprog gmail.com> wrote:

 On Friday, July 30, 2010 10:14:45 Steven Schveighoffer wrote:
 I think a function to do it is fine, like makeArray('-', 5);

Well, creating a function for producing an array literal and returning it using templates and string mixins wouldn't be all that hard, but if you want to create a dynamic array of arbitrary size at runtime, that's not going to work, and a makeArray() function would have exactly the same tools that you have to create an array of all the same value.

The function would call gc_malloc directly, which does not initialize the requested memory. Actually, it would call a new run time function that I will write, which would initialize the array length also.
 So, it's not going to be any more efficient that
 what you can do.

 int[] a = new int[](x);
 a[] = val;

 _should_ be fairly easily optimized by the compiler and thus really  
 should be
 optimized down to an initialization rather than an initialization and an
 assignment.

It's not. The only runtime functions available to the compiler look like this: _d_newarrayT(TypeInfo ti, size_t length); -Steve
Jul 30 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0016364d1c87045134048ca211bb
Content-Type: text/plain; charset=ISO-8859-1

 I don't know where such a tool should finally be placed in D, but I having
 it
 available as a library or as part of the language would be great.  It seems
 like a
 lot of other languages have it like python, perl, C++, and Java.  So it
 can't be
 that useless.

There is fill() in std.algorithm, but it needs an already present range... auto s = new int[5]; fill(s, 10); s is now [10,10,10,10,10] --0016364d1c87045134048ca211bb Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margi= n:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><br> I don&#39;t know where such a tool should finally be placed in D, but I hav= ing it<br> available as a library or as part of the language would be great. =A0It see= ms like a<br> lot of other languages have it like python, perl, C++, and Java. =A0So it c= an&#39;t be<br> that useless.<br></blockquote><div><br></div><div><br></div><div>There is f= ill() in std.algorithm, but it needs an already present range...</div><div>= <br></div><div>auto s =3D new int[5];</div><div>fill(s, 10);=A0</div><div> <br></div><div>s is now [10,10,10,10,10]</div><div><br></div><div>=A0</div>= </div><br> --0016364d1c87045134048ca211bb--
Jul 30 2010
prev sibling parent Jason Spencer <spencer8 sbcglobal.net> writes:
== Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 I was wrong, I looked through the runtime and did not find such a

std.string has a repeat() function. Try: import std.string; void main() { string divider = repeat("-", 5); writeln(divider); } Jason
Jul 31 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 30 Jul 2010 11:46:32 -0400, Justin Spahr-Summers  
<Justin.SpahrSummers gmail.com> wrote:

 On Fri, 30 Jul 2010 11:35:15 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 If you want to allocate a new array on the heap with '-' in it, I think
 there is a way, but I'm not sure how to do it.  I'm pretty sure there's  
 a
 runtime function to do it.

char[] divider = new char[5]; divider[] = '-';

That assigns 0xff to all divider chars, and then assigns '-'. I think there's a way to do it without the initial assignment. -Steve
Jul 30 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 30 Jul 2010 12:46:20 -0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 Steven Schveighoffer:
     char[] divider = new char[5];
     divider[] = '-';

That assigns 0xff to all divider chars, and then assigns '-'. I think there's a way to do it without the initial assignment.


I was wrong, I looked through the runtime and did not find such a function. I think I may have read it in my copy of TDPL that I reviewed. In any case, I think D deserves a way to do that.
 In past there was some way to do that:
 typedef char mchar = '-';
 mchar[] divider = new mchar[5];

As a way to initialize an array, this is horrible :)
 Now you have to initialize the dynamic array two times (using a char  
 struct with alias this is probably not a good idea).
 I have shown this problem, but I think Walter was not interested. Maybe  
 LDC will able to optimize away the first initialization, I have an  
 enhancement request for LLVM.

I think a function to do it is fine, like makeArray('-', 5); -Steve
Jul 30 2010
prev sibling next sibling parent reply =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 30-07-2010 o 17:24:41 dcoder <dcoder devnull.com> napisa=B3(a):

 Is there anyway in D to convenient fill a string variable with a char =

 say X times?

If you need to only print, you can: import std.stdio; import std.range; void main() { foreach (c; take(repeat('-'), 5)) write(c); } I know, I know, you said *convenient* ;) I heard write(ln) is to print = arbitrary ranges, so this'd come down to: writeln(take(repeat('-'), 5)); and if universal call syntax worked correctly then even this would be = possible: writeln('-'.repeat.take(5)); much easier to type. BTW, I stumbled on this when crafting the example: http://d.puremagic.com/issues/show_bug.cgi?id=3D4537 Tomek
Jul 30 2010
parent =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 30-07-2010 o 22:15:50 Tomek Sowi=F1ski <just ask.me> napisa=B3(a):

 writeln('-'.repeat.take(5));

Oh, and if repeat had slicing (as it should)... '-'.repeat[0..5] Still, it's far cry from Python's '-' * 5 Tomek
Jul 30 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Friday, July 30, 2010 13:10:46 Steven Schveighoffer wrote:
 On Fri, 30 Jul 2010 15:56:36 -0400, Jonathan M Davis
 
 <jmdavisprog gmail.com> wrote:
 On Friday, July 30, 2010 10:14:45 Steven Schveighoffer wrote:
 I think a function to do it is fine, like makeArray('-', 5);

Well, creating a function for producing an array literal and returning it using templates and string mixins wouldn't be all that hard, but if you want to create a dynamic array of arbitrary size at runtime, that's not going to work, and a makeArray() function would have exactly the same tools that you have to create an array of all the same value.

The function would call gc_malloc directly, which does not initialize the requested memory. Actually, it would call a new run time function that I will write, which would initialize the array length also.

Well, if there's a function other than new to allocate GC memory, then makeArray() is quite doable. I've never dealt with anything but new. As far as I've been aware, you either use new for GC memory or malloc for non-GC memory. If there's a gc_malloc, then that would solve the problem and it would make good sense to do that with makeArray().
 
 So, it's not going to be any more efficient that
 what you can do.
 
 int[] a = new int[](x);
 a[] = val;
 
 _should_ be fairly easily optimized by the compiler and thus really
 should be
 optimized down to an initialization rather than an initialization and an
 assignment.

It's not. The only runtime functions available to the compiler look like this: _d_newarrayT(TypeInfo ti, size_t length);

I guess that's one thing that comes of not really implementing it as a primitive. If there are enough such functions that would be properly optimizable had they actually been implemented as primitives, I would think that there would be some merit in finding a way to get the compiler to understand that it can do such optimizations. But I really don't know how all that works in dmd, so I have no idea how feasible that is. - Jonathan M Davis
Jul 30 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 30 Jul 2010 16:31:49 -0400, Jonathan M Davis  
<jmdavisprog gmail.com> wrote:

 On Friday, July 30, 2010 13:10:46 Steven Schveighoffer wrote:

 It's not.  The only runtime functions available to the compiler look  
 like
 this:

 _d_newarrayT(TypeInfo ti, size_t length);

I guess that's one thing that comes of not really implementing it as a primitive. If there are enough such functions that would be properly optimizable had they actually been implemented as primitives, I would think that there would be some merit in finding a way to get the compiler to understand that it can do such optimizations. But I really don't know how all that works in dmd, so I have no idea how feasible that is.

To be clear, the compiler could do the optimization if it had another runtime function to call. But since there is *no* runtime function that allocates a new array and initializes it with a custom initial element, how do you make a primitive? So if the function exists, the compiler can be fixed to make the sequence of "create then assign" a primitive, but I think just a runtime function is good enough, and will work without compiler changes. -Steve
Jul 30 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Friday, July 30, 2010 14:13:15 dcoder wrote:
 If I'm writing a program that pretty prints tree data, or output of sql,
 like Oracle's sqlplus, or postgres equivalent, I find having such a
 utility function/constructor a pretty handy feature.
 
 I don't know where such a tool should finally be placed in D, but I having
 it available as a library or as part of the language would be great.  It
 seems like a lot of other languages have it like python, perl, C++, and
 Java.  So it can't be that useless.

Well, I certainly have no problem with a function like makeArray() existing. It's just that it's one of those functions that I've never found useful, and I don't think that I've ever seen anyone use it in code. Now, for strings, I find such a function to be a bit dangerous since it's ignoring the fact that char is a UTF-8 code unit rather than an ASCII value, but for other types of arrays, that wouldn't be a problem. And for strings, you could either use dstrings or just be certain that all of your characters are actually a single code unit. But I certainly wouldn't want the equivalent of having a string constructor that takes a char and a count like C++'s string does. It would be fine in many cases, but string functions that take chars are generally asking for trouble due to unicode issues. But since, string in D is an array rather than a class, that's not really a problem in the same way. makeArray() being for arrays in general rather than specifically strings would not promote bad string code in the same way that C++'s string constructor does. - Jonathan M Davis
Jul 30 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 31 Jul 2010 05:37:41 -0400, Jason Spencer <spencer8 sbcglobal.net>  
wrote:

 == Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 I was wrong, I looked through the runtime and did not find such a

std.string has a repeat() function. Try: import std.string; void main() { string divider = repeat("-", 5); writeln(divider); }

It doesn't do the right thing. It allocates, then initializes, resulting in a double-initialization. -Steve
Aug 02 2010
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 30 Jul 2010 19:41:03 -0400, Justin Spahr-Summers  
<Justin.SpahrSummers gmail.com> wrote:

 On Fri, 30 Jul 2010 16:30:17 -0700, Jonathan M Davis
 <jmdavisprog gmail.com> wrote:
 On Friday, July 30, 2010 14:13:15 dcoder wrote:
 If I'm writing a program that pretty prints tree data, or output of  

 like Oracle's sqlplus, or postgres equivalent, I find having such a
 utility function/constructor a pretty handy feature.

 I don't know where such a tool should finally be placed in D, but I  

 it available as a library or as part of the language would be great.   

 seems like a lot of other languages have it like python, perl, C++,  

 Java.  So it can't be that useless.

Well, I certainly have no problem with a function like makeArray() existing. It's just that it's one of those functions that I've never found useful, and I don't think that I've ever seen anyone use it in code.


That's because it's not a trivial function to write :) One has to have intimate knowledge of the runtime and understand how to properly allocate a block for this purpose. Basically, there have been code instances of the form: T[] x = new T[n]; x[] = initval; Because that's the only way to do it. Offer a function like makeArray, and why *wouldn't* you change to it? I prefer a single line/initialization anyways.
 I agree with this sentiment. I think the feature is pretty niche to
 begin with, and the compiler should be able to optimize out the
 initialization in the sample I gave previously. D is indeed a systems
 language, but I (and I'm sure others) would like to use it in a high-
 level way, where I can write natural, straightforward code and expect
 the compiler to do the Right Thing.

I just find the syntax awkward: char[] divider = new char[5]; // hey, compiler I'm initializing divider divider[] = '-'; // OOHHH got you there, I wasn't done yet :) It just seems natural that I should be able to do this in one line. Having the compiler optimize isn't a bad thing, but relying on the optimization because "we can't find a better way" seems crappy to me.
 Besides, performance is not an applicable argument for this use case.
 Even if the array initialization is compiled into the binary, the amount
 of time it would take is infinitesimal. If someone's trying to
 initialize a 100,000 element array to some specific value, they're
 likely going to write their own makeArray() anyways.

The performance improvement is certainly a smaller argument compared to the syntax. But it is a nice bonus. There are more significant performance bugs in initialization of static arrays using array literals. -Steve
Aug 02 2010