www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Kill implicit joining of adjacent strings

reply bearophile <bearophileHUGS lycos.com> writes:
Do you seen anything wrong in this code? It compiles with no errors:

enum string[5] data = ["green", "magenta", "blue" "red", "yellow"];
static assert(data[4] == "yellow");
void main() {}


Yet that code asserts. it's an excellent example of why a sloppy
compiler/language sooner or later comes back to bite your ass.
I've recently had another bug caused by automatic joining of adjacent strings.
I think this is the 3rd I have found in my D code. This is enough.

In C the joining of adjacent strings is sometimes useful, but explicit is
better than implicit, and D has a short and good operator to perform joining of
strings, the ~, and D strings are allowed to span multi-lines.

C code ported to D that doesn't put a ~ just raises a compile time error that's
easy to understand and fix. So this doesn't change the meaning of C code, just
asks the programmer to improve the code, and the change requires is fully
mechanical.

The compiler need to be able to perform the joining at compile time, so zero
run-time overhead is present. The result is the same as before, it's just a
syntax change.

My bug report has more info and a partial patch:
http://d.puremagic.com/issues/show_bug.cgi?id=3827

Despite Walter seems to ignore C#, C# is a very well designed language,
polished, and indeed it refuses automatic joining of adjacent strings:

public class Test {
    public static void Main() {
        string s = "hello " "world";
    }
}

That C# code gives the error:

prog.cs(3,35): error CS1525: Unexpected symbol `world'
Compilation failed: 1 error(s), 0 warnings

This is one of the about twenty little/tiny changes I am waiting for D.

So please kill automatic joining of adjacent strings in D with fire.

Thank you,
bearophile
Nov 10 2010
next sibling parent reply Brad Roberts <braddr puremagic.com> writes:
Nagging is one way to accomplish change, but it's sure annoying.  If you feel
the feature is import, you know where to get the source.  Give it a shot.
Contribution of code is oh so much more valuable than a constant stream of "you
should change..."

Repeatedly claiming that Walter ignores 'X' is another way to get a reaction,
but it's also very annoying.  You're far from the only person to pull this card
out.  Do you _honestly_ believe he's that narrow minded or are you just trying
to get enough of a rise out of such claims that he'll drop what he's doing and
focus on your nag-of-the-day?

Sigh.. it get's old, fast.

Back to lurk mode,
Brad

On 11/10/2010 6:34 PM, bearophile wrote:
 Do you seen anything wrong in this code? It compiles with no errors:
 
 enum string[5] data = ["green", "magenta", "blue" "red", "yellow"];
 static assert(data[4] == "yellow");
 void main() {}
 
 
 Yet that code asserts. it's an excellent example of why a sloppy
compiler/language sooner or later comes back to bite your ass.
 I've recently had another bug caused by automatic joining of adjacent strings.
I think this is the 3rd I have found in my D code. This is enough.
 
 In C the joining of adjacent strings is sometimes useful, but explicit is
better than implicit, and D has a short and good operator to perform joining of
strings, the ~, and D strings are allowed to span multi-lines.
 
 C code ported to D that doesn't put a ~ just raises a compile time error
that's easy to understand and fix. So this doesn't change the meaning of C
code, just asks the programmer to improve the code, and the change requires is
fully mechanical.
 
 The compiler need to be able to perform the joining at compile time, so zero
run-time overhead is present. The result is the same as before, it's just a
syntax change.
 
 My bug report has more info and a partial patch:
 http://d.puremagic.com/issues/show_bug.cgi?id=3827
 
 Despite Walter seems to ignore C#, C# is a very well designed language,
polished, and indeed it refuses automatic joining of adjacent strings:
 
 public class Test {
     public static void Main() {
         string s = "hello " "world";
     }
 }
 
 That C# code gives the error:
 
 prog.cs(3,35): error CS1525: Unexpected symbol `world'
 Compilation failed: 1 error(s), 0 warnings
 
 This is one of the about twenty little/tiny changes I am waiting for D.
 
 So please kill automatic joining of adjacent strings in D with fire.
 
 Thank you,
 bearophile

Nov 10 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Brad Roberts:

 Nagging is one way to accomplish change, but it's sure annoying.

Right. I was a little too much nervous, sometimes I need to control myself a little more :-)
 If you feel the feature is import, you know where to get the source.  Give it
a shot.

There is already a partial patch. And modifying just my own version of D is less than useless.
 Contribution of code is oh so much more valuable than a constant stream of "you
 should change..."

Right.
 Repeatedly claiming that Walter ignores 'X' is another way to get a reaction,
 but it's also very annoying.  You're far from the only person to pull this card
 out.  Do you _honestly_ believe he's that narrow minded or are you just trying
 to get enough of a rise out of such claims that he'll drop what he's doing and
 focus on your nag-of-the-day?

I don't fully understand you. He sometimes ignores 'X', but he's busy, so I don't expect him to know everything. This is why I have written this and other posts, to not let this X be ignored. I am not asking to remove implicit joining of adjacent strings today, but I'd like this to be considered for future change.
 Sigh.. it get's old, fast.

I don't understamd this speech figure, sorry. Bye, bearophile
Nov 10 2010
prev sibling next sibling parent reply "Yao G." <yao.gomez spam.gmail.com> writes:
On Wed, 10 Nov 2010 20:34:07 -0600, bearophile <bearophileHUGS lycos.com>  
wrote:

 Do you seen anything wrong in this code? It compiles with no errors:

 enum string[5] data = ["green", "magenta", "blue" "red", "yellow"];
 static assert(data[4] == "yellow");
 void main() {}


 Yet that code asserts. it's an excellent example of why a sloppy  
 compiler/language sooner or later comes back to bite your ass.

Stop blaming the compiler for your own carelessness.
 In C the joining of adjacent strings is sometimes useful, but explicit  
 is better than implicit, and D has a short and good operator to perform  
 joining of strings, the ~, and D strings are allowed to span multi-lines.

I find it useful, and I like it. I like to break long strings into smaller ones and put each one in one line. I know that you can do that using one single string, but some syntax hightlighters don't like it that way.
 Despite Walter seems to ignore C#, C# is a very well designed language,  
 polished, and indeed it refuses automatic joining of adjacent strings:
 [...]
 This is one of the about twenty little/tiny changes I am waiting for D.

Maybe you should switch to C# :)
 So please kill automatic joining of adjacent strings in D with fire.

No.
 Thank you,
 bearophile

-- Yao G.
Nov 10 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Yao G.:

 Stop blaming the compiler for your own carelessness.

If a simple common human error is avoidable at compile-time then it's the duty of the compiler to avoid it. Blaming the programmer is just silly (and it's against one of the main "philosophical" differences between C and D). I suggest you to read some books by Donald Norman about the design of everyday things, and their error-prone interfaces, that explain very well why you are very wrong: http://en.wikipedia.org/wiki/Donald_Norman
 I find it useful, and I like it. I like to break long strings into smaller ones
 and put each one in one line. I know that you can do that using one single  
 string, but
 some syntax hightlighters don't like it that way.

This string of yours: string someText = "I find it useful, and I like it. I like to break long strings into smaller ones" "and put each one in one line. I know that you can do that using one single string, but" "some syntax hightlighters don't like it that way."; Now becomes: string someText = "I find it useful, and I like it. I like to break long strings into smaller ones" ~ "and put each one in one line. I know that you can do that using one single string, but" ~ "some syntax hightlighters don't like it that way."; Bye, bearophile
Nov 10 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
so:

 For 3 lines yes but how about a long file? Not everyone using vim!

There is very little D2 code around... and I don't think very large amounts of concatenated strings in the source code are a good programming practice.
 What about this one?
 
 "red" "blue" => error
 
 "red"
 "blue" => pass

That's a special case, special cases are bad for the programmer's diet :-) Bye, bearophile
Nov 10 2010
parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 11.11.2010 11:16, schrieb spir:
 On Wed, 10 Nov 2010 23:10:35 -0500
 bearophile<bearophileHUGS lycos.com>  wrote:

  >  For 3 lines yes but how about a long file? Not everyone using vim!

  There is very little D2 code around... and I don't think very large amounts
of concatenated strings in the source code are a good programming practice.

Can't insertion of '~' be easily automated, for extreme cases? Denis -- -- -- -- -- -- -- vit esse estrany � spir.wikidot.com

or please, all around stop asking for stuff like that, what in hell is the benefit, are all developers around my just typing in orgies for strings into its sources and these n "~" are too much... i don't get it
Nov 11 2010
parent dennis luehring <dl.soluz gmx.net> writes:
Am 11.11.2010 14:28, schrieb spir:
 On Thu, 11 Nov 2010 11:18:19 +0100
 dennis luehring<dl.soluz gmx.net>  wrote:

  Am 11.11.2010 11:16, schrieb spir:
  >  On Wed, 10 Nov 2010 23:10:35 -0500
  >  bearophile<bearophileHUGS lycos.com>   wrote:
  >
  >>   >   For 3 lines yes but how about a long file? Not everyone using vim!
  >>
  >>   There is very little D2 code around... and I don't think very large
amounts of concatenated strings in the source code are a good programming
practice.
  >
  >  Can't insertion of '~' be easily automated, for extreme cases?
  >
  >  Denis
  >  -- -- -- -- -- -- --
  >  vit esse estrany âᅵ£
  >
  >  spir.wikidot.com
  >

  or please, all around stop asking for stuff like that, what in hell is
  the benefit, are all developers around my just typing in orgies for
  strings into its sources and these n "~" are too much... i don't get it

Man, you misunderstood. I meant a transition tool to help with imcompatibility.

got it, but do you really thing it will be used that much - i can't remember more that 10 occurences of this in the last 14 years (and mio. lines of readed code) its in whole a complete useless discussion, remove it as fast as possible - i personaly think, no one will ever cry because of this
 Denis
 -- -- -- -- -- -- --
 vit esse estrany �

 spir.wikidot.com

Nov 11 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday 10 November 2010 18:56:02 Brad Roberts wrote:
 Nagging is one way to accomplish change, but it's sure annoying.  If you
 feel the feature is import, you know where to get the source.  Give it a
 shot. Contribution of code is oh so much more valuable than a constant
 stream of "you should change..."
 
 Repeatedly claiming that Walter ignores 'X' is another way to get a
 reaction, but it's also very annoying.  You're far from the only person to
 pull this card out.  Do you _honestly_ believe he's that narrow minded or
 are you just trying to get enough of a rise out of such claims that he'll
 drop what he's doing and focus on your nag-of-the-day?
 
 Sigh.. it get's old, fast.

If nothing else, the sheer number of requests guarantees that they won't all be done even if they were all great and really should be done. Bearophile does have a lot of good things to say, but he says so much so often that sometimes it becomes hard not to just tune him out. As for this particular request, I tend to agree. I don't see in point in adjacent strings concatenating. I never write my code that way, and it does seem error-prone. I'm not sure that I'm all that against it being in the language, but if it were my choice, I wouldn't have had it. - Jonathan M Davis
Nov 10 2010
prev sibling next sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Thu, 11 Nov 2010 04:34:07 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 So please kill automatic joining of adjacent strings in D with fire.

Yes please. I didn't even know this feature existed in D, but I was recently bitten by a bug in a C++ program - also due to a missing comma in an array of string literals. Yao G.: use ~. -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Nov 10 2010
prev sibling next sibling parent so <so so.do> writes:
 "blue" "red"

I guess it exists because of a few use cases other than this one. For this particular example, you are right i couldn't see it and i checked two times! -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 10 2010
prev sibling next sibling parent so <so so.do> writes:
 string someText = "I find it useful, and I like it. I like to break long  
 strings into smaller ones"
     "and put each one in one line. I know that you can do that using one  
 single string, but"
     "some syntax hightlighters don't like it that way.";

 Now becomes:

 string someText = "I find it useful, and I like it. I like to break long  
 strings into smaller ones" ~
     "and put each one in one line. I know that you can do that using one  
 single string, but" ~
     "some syntax hightlighters don't like it that way.";

 Bye,
 bearophile

For 3 lines yes but how about a long file? Not everyone using vim! What about this one? "red" "blue" => error "red" "blue" => pass -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 10 2010
prev sibling next sibling parent reply Rainer Deyke <rainerd eldwood.com> writes:
On 11/10/2010 19:34, bearophile wrote:
 Do you seen anything wrong in this code? It compiles with no errors:
 
 enum string[5] data = ["green", "magenta", "blue" "red", "yellow"];
 static assert(data[4] == "yellow");
 void main() {}
 
 
 Yet that code asserts.

Wait, what? That's a static assert. How can it both assert and compile with no errors? As it turns out, the joining of adjacent strings is a critical feature. Consider the following: f("a" "b"); f("a" ~ "b"); These are /not/ equivalent. In the former cases, 'f' receives a string literal as argument, which means that the string is guaranteed to be zero terminated. In the latter case, 'f' receives an expression (which can be evaluated at compile time) as argument, so the string may not be zero terminated. This is a critical difference if 'f' is a (wrapper around a) C function. -- Rainer Deyke - rainerd eldwood.com
Nov 10 2010
next sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Thu, 11 Nov 2010 06:51:38 +0200, Rainer Deyke <rainerd eldwood.com>  
wrote:

 On 11/10/2010 19:34, bearophile wrote:
 Do you seen anything wrong in this code? It compiles with no errors:

 enum string[5] data = ["green", "magenta", "blue" "red", "yellow"];
 static assert(data[4] == "yellow");
 void main() {}


 Yet that code asserts.

Wait, what? That's a static assert. How can it both assert and compile with no errors? As it turns out, the joining of adjacent strings is a critical feature. Consider the following: f("a" "b"); f("a" ~ "b"); These are /not/ equivalent. In the former cases, 'f' receives a string literal as argument, which means that the string is guaranteed to be zero terminated. In the latter case, 'f' receives an expression (which can be evaluated at compile time) as argument, so the string may not be zero terminated. This is a critical difference if 'f' is a (wrapper around a) C function.

Wait, so you imply that if I pass 2+2 as a parameter to a function with lazy parameters, the compiler should not do partial expression calculation and should actually add up 2+2 at runtime? Because, AFAICS, concatenating two string literals should be no different from adding two numbers. -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Nov 10 2010
prev sibling next sibling parent reply Don <nospam nospam.com> writes:
Rainer Deyke wrote:
 On 11/10/2010 19:34, bearophile wrote:
 Do you seen anything wrong in this code? It compiles with no errors:

 enum string[5] data = ["green", "magenta", "blue" "red", "yellow"];
 static assert(data[4] == "yellow");
 void main() {}


 Yet that code asserts.

Wait, what? That's a static assert. How can it both assert and compile with no errors? As it turns out, the joining of adjacent strings is a critical feature. Consider the following: f("a" "b"); f("a" ~ "b"); These are /not/ equivalent. In the former cases, 'f' receives a string literal as argument, which means that the string is guaranteed to be zero terminated. In the latter case, 'f' receives an expression (which can be evaluated at compile time) as argument, so the string may not be zero terminated. This is a critical difference if 'f' is a (wrapper around a) C function.

But in D, unlike C and C++, constant folding is guaranteed to happen for built-in types (and it happens in the semantic pass, not in the backend). So in reality, there's no difference. The docs just need to state that (string literal ~ string literal) is still null terminated -- that's the only thing that is missing.
Nov 11 2010
parent reply "Manfred_Nowak" <svv1999 hotmail.com> writes:
Don wrote:

 that's the only thing that is missing

Disagreed. One of the main points of all languages is to emphasize ones aim, espacially if there is a chance of misinterpretation because of the language. Example: there is only a tiny change in the characters from `31415' to ` 3.1415'. Without function overloading this can be detected in D, because the type of actual parameters changes and Walter dismissed automatic type changes from `real' to `int'. The situation the OP described sams quite similar to me. -manfred
Nov 11 2010
parent reply Don <nospam nospam.com> writes:
Manfred_Nowak wrote:
 Don wrote:
 
 that's the only thing that is missing

Disagreed. One of the main points of all languages is to emphasize ones aim, espacially if there is a chance of misinterpretation because of the language. Example: there is only a tiny change in the characters from `31415' to ` 3.1415'. Without function overloading this can be detected in D, because the type of actual parameters changes and Walter dismissed automatic type changes from `real' to `int'. The situation the OP described sams quite similar to me. -manfred

I was replying to Rainer, not to the OP. At present in the compiler there is no difference between "a" "b" and "a" ~ "b". So implicit joining could be disallowed with loss of functionality. But that fact isn't clear from the docs.
Nov 11 2010
next sibling parent "Manfred_Nowak" <svv1999 hotmail.com> writes:
Don wrote:

 But that fact isn't clear from the docs.

Thx for the clarification. -manfred
Nov 11 2010
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/11/10 4:36 AM, Don wrote:
 Manfred_Nowak wrote:
 Don wrote:

 that's the only thing that is missing

Disagreed. One of the main points of all languages is to emphasize ones aim, espacially if there is a chance of misinterpretation because of the language. Example: there is only a tiny change in the characters from `31415' to ` 3.1415'. Without function overloading this can be detected in D, because the type of actual parameters changes and Walter dismissed automatic type changes from `real' to `int'. The situation the OP described sams quite similar to me. -manfred

I was replying to Rainer, not to the OP. At present in the compiler there is no difference between "a" "b" and "a" ~ "b". So implicit joining could be disallowed with loss of functionality. But that fact isn't clear from the docs.

Well the story is a tad longer. Associativity must be also taken into account. Consider: string s = readText("/path/to/file"); writeln("The " ~ " text is: " ~ s ~ "\n" ~ " === " ~ "\n end.\n"); In this case, the compiler must look ahead to concatenate all literal strings in the expression before concatenating with s. Since ~ is just left-associative, then we have a special rule on our hands. I think removing literal concatenation wouldn't harm. There is an unwritten rule in the back of my mind that a language should be designed such that inserting or removing a punctuation sign in a program does not change the semantics of the program. This may not be always attainable, but it's a good goal to live into. I remember this story about a mission-critical Fortran program blew up because of a punctuation character in the wrong place. Regarding the dimension of this problem, I don't think there's a lot of evidence there. C and C++ have had implicit concatenation of string literals forever, but I've never read or heard anywhere about that issue being even on the radar. Andrei
Nov 11 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Rainer Deyke:

 Wait, what?  That's a static assert.  How can it both assert and compile
 with no errors?

You are right, what I meant is that if you remove the assert the program compiles with no errors (also note the number 5 that is different from 4 strings): enum string[5] data = ["green", "magenta", "blue" "red", "yellow"]; void main() {}
 In the latter case, 'f' receives an expression (which
 can be evaluated at compile time) as argument,

I meant the concatenation to be evaluated at compile-time for sure, so there is zero runtime overhead.
 so the string may not be
 zero terminated.  This is a critical difference if 'f' is a (wrapper
 around a) C function.

I hope Don's idea on this (thank you Don) will be enough. --------------------- Again, sorry for the tone of my original post of this thread. Bye, bearophile
Nov 11 2010
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-11-10 23:51:38 -0500, Rainer Deyke <rainerd eldwood.com> said:

 As it turns out, the joining of adjacent strings is a critical feature.
  Consider the following:
   f("a" "b");
   f("a" ~ "b");
 These are /not/ equivalent.  In the former cases, 'f' receives a string
 literal as argument, which means that the string is guaranteed to be
 zero terminated.  In the latter case, 'f' receives an expression (which
 can be evaluated at compile time) as argument, so the string may not be
 zero terminated.  This is a critical difference if 'f' is a (wrapper
 around a) C function.

You worry too much. With 'f' a wrapper around a C function that takes a const(char)* argument, if the argument is not a literal string then it won't compile. Only string literals are implicitly convertible to const(char)*, not 'string' variables. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Nov 11 2010
parent reply Rainer Deyke <rainerd eldwood.com> writes:
On 11/11/2010 06:06, Michel Fortin wrote:
 On 2010-11-10 23:51:38 -0500, Rainer Deyke <rainerd eldwood.com> said:
 
 As it turns out, the joining of adjacent strings is a critical feature.
  Consider the following:
   f("a" "b");
   f("a" ~ "b");
 These are /not/ equivalent.  In the former cases, 'f' receives a string
 literal as argument, which means that the string is guaranteed to be
 zero terminated.  In the latter case, 'f' receives an expression (which
 can be evaluated at compile time) as argument, so the string may not be
 zero terminated.  This is a critical difference if 'f' is a (wrapper
 around a) C function.

You worry too much. With 'f' a wrapper around a C function that takes a const(char)* argument, if the argument is not a literal string then it won't compile. Only string literals are implicitly convertible to const(char)*, not 'string' variables.

You just restated the problem. There needs to be a way to break up string literals while still treating them as a single string literal that is convertible to 'const(char)*'. You could overload binary '~' for this, but I think this may be confusing. -- Rainer Deyke - rainerd eldwood.com
Nov 11 2010
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-11-11 15:05:08 -0500, Rainer Deyke <rainerd eldwood.com> said:

 On 11/11/2010 06:06, Michel Fortin wrote:
 On 2010-11-10 23:51:38 -0500, Rainer Deyke <rainerd eldwood.com> said:
 
 As it turns out, the joining of adjacent strings is a critical feature.
 Consider the following:
 f("a" "b");
 f("a" ~ "b");
 These are /not/ equivalent.  In the former cases, 'f' receives a string
 literal as argument, which means that the string is guaranteed to be
 zero terminated.  In the latter case, 'f' receives an expression (which
 can be evaluated at compile time) as argument, so the string may not be
 zero terminated.  This is a critical difference if 'f' is a (wrapper
 around a) C function.

You worry too much. With 'f' a wrapper around a C function that takes a const(char)* argument, if the argument is not a literal string then it won't compile. Only string literals are implicitly convertible to const(char)*, not 'string' variables.

You just restated the problem. There needs to be a way to break up string literals while still treating them as a single string literal that is convertible to 'const(char)*'. You could overload binary '~' for this, but I think this may be confusing.

Perhaps I misstated things a bit. Only *compile-time* strings are implicitly convertible to const(char)*. The expression "abc"~"def" is a string known at compile-time, and is written in the object file as one string literal. Note that compile-time strings could also come from enums and templates. This will be written as one string literal in the object file: enum hello = "hello"; template T(alias s) { enum T = s; } unittest { f(hello ~ T!"world"); } This call to 'f' works because hello~T!"world" forms a compile-time string and is implicitly convertible to a const(char)*. Try it! Also try changing 'enum' with 'auto' to make hello a variable and it'll no longer work. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Nov 11 2010
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 11 Nov 2010 10:03:58 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 11/11/10 4:36 AM, Don wrote:
 Manfred_Nowak wrote:
 Don wrote:

 that's the only thing that is missing

Disagreed. One of the main points of all languages is to emphasize ones aim, espacially if there is a chance of misinterpretation because of the language. Example: there is only a tiny change in the characters from `31415' to ` 3.1415'. Without function overloading this can be detected in D, because the type of actual parameters changes and Walter dismissed automatic type changes from `real' to `int'. The situation the OP described sams quite similar to me. -manfred

I was replying to Rainer, not to the OP. At present in the compiler there is no difference between "a" "b" and "a" ~ "b". So implicit joining could be disallowed with loss of functionality. But that fact isn't clear from the docs.

Well the story is a tad longer. Associativity must be also taken into account. Consider: string s = readText("/path/to/file"); writeln("The " ~ " text is: " ~ s ~ "\n" ~ " === " ~ "\n end.\n"); In this case, the compiler must look ahead to concatenate all literal strings in the expression before concatenating with s. Since ~ is just left-associative, then we have a special rule on our hands.

Hm... testing it appears you are right -- the compiler folds "The " ~ " text is: " together, but not the elements after s. Even with optimization turned on. I would think it would, considering it should fold "abc" "def" currently. This means it already has to look ahead to see if "abc" is indeed the end of the literal. Can't we just change that rule? In other words, get rid of one special rule and replace it with another? IMO, this is actually bad that the compiler does not fold concatenated string literals in all cases. Don, maybe you can file a bug on that?
 Regarding the dimension of this problem, I don't think there's a lot of  
 evidence there. C and C++ have had implicit concatenation of string  
 literals forever, but I've never read or heard anywhere about that issue  
 being even on the radar.

Well, it's also the only way to concatenate literals together in C++/C. So even if there were complaints, there was a legitimate reason to keep it. People tend not to complain as much when there are valid reasons to have something. Compare that to if(x); where there is no valid reason to have it. Give C++/C a way to concatenate literals together the way D can, and this might change. But besides all that, it looks like a no-brainer to me -- we have equivalent syntax that works (or at least should work) the same, and the alternative syntax is not ambiguous and prone to error. -Steve
Nov 11 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Wed, 10 Nov 2010 23:10:35 -0500
bearophile <bearophileHUGS lycos.com> wrote:

 For 3 lines yes but how about a long file? Not everyone using vim! =20

There is very little D2 code around... and I don't think very large amoun=

ce. Can't insertion of '~' be easily automated, for extreme cases?=20 Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 11 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 10 Nov 2010 21:34:07 -0500, bearophile <bearophileHUGS lycos.com>  
wrote:

 Do you seen anything wrong in this code? It compiles with no errors:

 enum string[5] data = ["green", "magenta", "blue" "red", "yellow"];
 static assert(data[4] == "yellow");
 void main() {}


 Yet that code asserts. it's an excellent example of why a sloppy  
 compiler/language sooner or later comes back to bite your ass.
 I've recently had another bug caused by automatic joining of adjacent  
 strings. I think this is the 3rd I have found in my D code. This is  
 enough.

 In C the joining of adjacent strings is sometimes useful, but explicit  
 is better than implicit, and D has a short and good operator to perform  
 joining of strings, the ~, and D strings are allowed to span multi-lines.

100% agree. Get rid of it. My suggestion is to make auto-concatenation an error and see how many unintended errors there are in phobos. This model of testing has helped to explain how features are bug prone in the past. -Steve P.S. WRT bearophile's constant nagging, I agree it's not the best way to be heard. But if you feel strongly about something, and it's not getting attention, I don't see another way. Note that if you didn't continuously nag about stylistic issues that are very subjective, nagging about real problems like this would carry more weight. I wrote a very similar post that resulted in the destruction of class == null from the language (ironically, I think it could be inserted back into the language now that object.opEquals is called instead).
Nov 11 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Thu, 11 Nov 2010 11:18:19 +0100
dennis luehring <dl.soluz gmx.net> wrote:

 Am 11.11.2010 11:16, schrieb spir:
 On Wed, 10 Nov 2010 23:10:35 -0500
 bearophile<bearophileHUGS lycos.com>  wrote:

  >  For 3 lines yes but how about a long file? Not everyone using vim!

  There is very little D2 code around... and I don't think very large a=



actice.
 Can't insertion of '~' be easily automated, for extreme cases?

 Denis
 -- -- -- -- -- -- --
 vit esse estrany =C3=A2=EF=BF=BD=C2=A3

 spir.wikidot.com

or please, all around stop asking for stuff like that, what in hell is=20 the benefit, are all developers around my just typing in orgies for=20 strings into its sources and these n "~" are too much... i don't get it

Man, you misunderstood. I meant a transition tool to help with imcompatibil= ity. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 11 2010
prev sibling parent klickverbot <see klickverbot.at> writes:
+1 on this.

While implicit joining can certainly be useful in C in some cases, D has 
the ~ operator for such cases.

Since compile-time primitives are guaranteed to be folded anyway (IIRC), 
I can imagine no situation where the benefits of banning implicit 
joining (reducing the chance for bugs, less special cases) would not 
outweigh the costs of an additional character to type.
Nov 11 2010