February 27, 2020
On Thu, Feb 27, 2020 at 11:26:37AM -0800, Walter Bright via Digitalmars-d-announce wrote: [...]
> Magic types are not simple and inevitably lead to unexpected corners and unresolvable problems. *cough* associative arrays *cough*
[...]

For all the trouble they've given us, built-in AA's is one of the primary reasons I love D.

IMO, it's inexcusible for a programming language in this day and age not to have built-in AA's, either as part of the language, or as part of the standard library -- but with FULL LANGUAGE SUPPORT.  Meaning that all built-in types can be used as AA keys without further ado, unlike C++'s standard hashtable which IMNSHO is a horrible piece of nigh-unusable crap, because you can't even declare a hashtable without defining your own hash function, you can't use structs as keys unless you also manually declare a hash function, a comparison function, and who knows what other onerous detail I can't recall, and then you have to use that horrendous iterator API to lookup anything at all.

Once, I wanted to add a simple hashtable as a caching mechanism to one of my C++ projects. After *two days* it still wasn't working properly, because there is no default hash function for anything, not even ints, so I have to write my own, and the hash function must be wrapped in some kind of functional wrapper object because you can't pass functions to the template parameter, then to initialize the hashtable I have to jump through a whole bunch of hoops, mostly involving the fact that to create the hash function object I needed to pass the necessary context all over the place -- so I had to rewrite 70% of the internal API just to be able to pass the context to the right places. Then the dumb thing required C++11 or something like that, which broke my C++98 code in horrendous ways that required a full-scale refactor to fix some of the incompatibilities.

Eventually I threw in the towel, and spent about a month's time to rewrite the whole danged project in D -- from scratch. I can't describe how refreshing it was to be able to just write:

	Value[Key] aa;

and that's *it*.  No fuss, no muss, it Just Works(tm).  Sure, when there's a performance issue then I have to add opHash or opEquals or what-not to my types, but the important thing is, there are *sane defaults* for everything.  The compiler isn't going to throw my code back in my face just because I used a custom type instead of string for the AA key (some languages have this problem), and the custom type may contain other custom types but it just knows to compute the default hash value accordingly.

If D *didn't* have .opHash built-in, it would've been a totally different story, probably not too unlike my horrible experience with C++.  If there wasn't a default hash function, and if I had to manually declare a whole bunch of stuff just to be able to use a struct containing a pair of ints as key, then it would have been a horrendous experience.


TL;DR: I'm *glad* D has built-in AA's, in spite of whatever flaws they may have.  It was the Right Choice, even though the execution, in retrospect, was a bit wanting.


T

-- 
MSDOS = MicroSoft's Denial Of Service
February 27, 2020
On 2/27/2020 3:44 AM, aliak wrote:
> Btw: Swift does this for string interpolation and it works very well -> https://www.hackingwithswift.com/articles/178/super-powered-string-interpolation-in-swift-5-0 

I don't know Swift, but this looks like the "generate strings and concatenate them" approach.

February 28, 2020
On Friday, 28 February 2020 at 03:10:48 UTC, Walter Bright wrote:

> I don't know Swift, but this looks like the "generate strings and concatenate them" approach.

No, it basically lowers to bunch of method calls. Here's an example of how it could look like with D syntax:

auto a = 3;
auto b = i"foo $a bar";

Could be lowered to:

auto _temp = StringInterpolation(8 /* literal capacity */, 1 /* interpolation count */);
_temp.appendLiteral("foo ");
_temp.appendInterpolation(a);
_temp.appendLiteral(" bar");
auto b = _temp.toString();

There's nothing here that says that this needs to use the GC to allocate the final string. "StringInterpolation" could contain something like OutBuffer from DMD or, if the arguments were passed as template arguments, it could allocate on the stack.

--
/Jacob Carlborg


February 28, 2020
On Thursday, 27 February 2020 at 18:58:40 UTC, Walter Bright wrote:
> On 2/27/2020 1:45 AM, Rainer Schuetze wrote:
>> The string buffer could also be stack allocated or manually managed with
>> malloc/free by the string interpolation type.
>
> It's quite a big deal to make that work, and does not address the inherent inefficiency of it.
>
> printf, for all its faults, is very efficient, and one reason is it does not require arbitrary temporary storage. Another is it does not require exception handlers. I, for one, simply would not use such when printf is available.

It isn't that efficient. There are a lot of implementations faster than it, and funnily enough they allocate memory, use exceptions, and RAII.

> People often overlook how *expensive* RAII is. Turn exception handling on and have a look at the generated code.

There was a whole other thread about this, and people found the assembly generated isn't all that different. Yes throwing exceptions is expensive, but what you are talking about, the cost of not throwing them, it really isn't. You are making it out to be a bigger problem than it actually is. If it caused such a huge performance hit, then exceptions simply wouldn't be used at all in C++. But that's not the case.

> It's a minor syntactic convenience with an unexpected large and hidden cost. That's not what D is about.
>
> Leave this at the user's discretion with:
>
>     f(format("hello %betty"));
>
> where the user chooses via the format function which method of handling temporaries he finds appropriate.

There are quite a few places that D has large hidden costs. Hell GC and any feature or otherwise that uses it is a large and hidden cost. You can't really say D is not about unexpected large and hidden costs when it has a GC integrated into quite a few features that make it invisible.



February 28, 2020
On Thursday, 27 February 2020 at 14:32:29 UTC, Petar Kirov [ZombineDev] wrote:
> On Thursday, 27 February 2020 at 09:30:30 UTC, Walter Bright wrote:
>> Rust does not follow C syntax at all, so nobody will reasonably expect it to have C semantics. D does follow it, it's a feature, so people will have expectations.
>
> I'm not sure where exactly you draw the line, but I would say that C# follows C's syntax about as much as D does. Yet it doesn't import some of the broken C semantics like implicit narrowing conversions (luckily, neither does D) and allowing mixed sign comparisons (the oldest open D issue :( [0]).
>
> My point is that if D didn't follow the usual arithmetic conversions, much fewer newcomers would even notice compared to extremely large backlash that we may get if go with the string interpolation -> raw tuple approach.
>
> [0]: https://issues.dlang.org/show_bug.cgi?id=259

Funnily enough the only contribution by Walter in that 14 year old bug is him trying to close it without there having been a solution implemented.

The spec is also still wrong, after 14 years.

https://dlang.org/spec/expression.html#integer_comparisons
February 28, 2020
On Thursday, 27 February 2020 at 20:00:52 UTC, H. S. Teoh wrote:
> On Thu, Feb 27, 2020 at 11:26:37AM -0800, Walter Bright via Digitalmars-d-announce wrote: [...]
>> [...]
> [...]
>
> For all the trouble they've given us, built-in AA's is one of the primary reasons I love D.
>
> [...]

The reason for C++ forcing users to do that is the lack of compile-time reflection.
February 28, 2020
On Fri, Feb 28, 2020 at 05:45:35PM +0000, Atila Neves via Digitalmars-d-announce wrote:
> On Thursday, 27 February 2020 at 20:00:52 UTC, H. S. Teoh wrote:
[...]
> > For all the trouble they've given us, built-in AA's is one of the
> > primary reasons I love D.
> > [...]
> 
> The reason for C++ forcing users to do that is the lack of compile-time reflection.

Whatever the reason may be, the result is a total usability nightmare compared to D's convenience.  Even a supposedly "flawed" feature like AA's in D compares favorably to C++; I seriously can't bring myself to write C++ code anymore.  D has ruined my life. :-P


T

-- 
Those who don't understand D are condemned to reinvent it, poorly. -- Daniel N
February 28, 2020
On 2/28/20 5:17 AM, Jacob Carlborg wrote:
> On Friday, 28 February 2020 at 03:10:48 UTC, Walter Bright wrote:
> 
>> I don't know Swift, but this looks like the "generate strings and concatenate them" approach.
> 
> No, it basically lowers to bunch of method calls. Here's an example of how it could look like with D syntax:
> 
> auto a = 3;
> auto b = i"foo $a bar";
> 
> Could be lowered to:
> 
> auto _temp = StringInterpolation(8 /* literal capacity */, 1 /* interpolation count */);
> _temp.appendLiteral("foo ");
> _temp.appendInterpolation(a);
> _temp.appendLiteral(" bar");
> auto b = _temp.toString();

I think Walter's point is that swift is still appending strings and then returning that. This requires allocations, and is not as preferable as directly processing the data. Not only that, but it's generating temporary strings just to add them to the larger thing that will be printed (I'm assuming this is not just a big string but an array/list, due to the beginning of the video and s1+s2+s3+s4).

I'd much prefer for example, printing using DIP1027 than constructing a string (even if the memory is reasonably fast, like malloc) just to throw it away.

I watched a lot of that video, it didn't impress me much. I use swift interpolation strings quite a bit, and they are useful. But I think D's will be much more performant and more straightforward for hooking (if they ever get in).

-Steve
February 29, 2020
On Friday, 28 February 2020 at 19:16:08 UTC, Steven Schveighoffer wrote:
> On 2/28/20 5:17 AM, Jacob Carlborg wrote:
>> On Friday, 28 February 2020 at 03:10:48 UTC, Walter Bright wrote:
>> 
>>> I don't know Swift, but this looks like the "generate strings and concatenate them" approach.
>> 
>> No, it basically lowers to bunch of method calls. Here's an example of how it could look like with D syntax:
>> 
>> auto a = 3;
>> auto b = i"foo $a bar";
>> 
>> Could be lowered to:
>> 
>> auto _temp = StringInterpolation(8 /* literal capacity */, 1 /* interpolation count */);
>> _temp.appendLiteral("foo ");
>> _temp.appendInterpolation(a);
>> _temp.appendLiteral(" bar");
>> auto b = _temp.toString();
>
> I think Walter's point is that swift is still appending strings and then returning that. This requires allocations, and is not as preferable as directly processing the data. Not only that, but it's generating temporary strings just to add them to the larger thing that will be printed (I'm assuming this is not just a big string but an array/list, due to the beginning of the video and s1+s2+s3+s4).
>
> I'd much prefer for example, printing using DIP1027 than constructing a string (even if the memory is reasonably fast, like malloc) just to throw it away.
>
> I watched a lot of that video, it didn't impress me much. I use swift interpolation strings quite a bit, and they are useful. But I think D's will be much more performant and more straightforward for hooking (if they ever get in).
>
> -Steve

I actually didn't realize it was a video, thought it was just an article! - But anyway, it was just to point out that swift lowers to specialized types when it comes to interpolation (which is what you and adam are trying to get through). And therefor you can detect interpolations being given to you and deal with them the way you want and you can do a lot when you know you're getting an interpolation. You can create types like

let example: SQLStatment = "select * from blah where a=\(a), b=\(b) ... "

I also didn't realize the takeaway would be that swift does appending 😆- which by the way, is not completely accurate. And it does not generate temporaries (unless you mean passing in parameters? There's no way around that if you want to end up with a string based on runtime values - it'll have to be processed in to a string somewhere).

You can also get an interpolated string directly in to "print processing" if you wanted to: https://swift.godbolt.org/z/muAzgm

And for the record I think the tuple generation is great as well. I highly doubt it'll be easier to use than swift (case in point: no need to call idup or whatever to convert to a string, since a string in swift is a type that is "interpolation aware"). Hook in to maybe, it depends on the APIs provided to hook in to them. An opaque type will not be easier to hook in to and a "concrete" named interface (aka protocol in swift).

When it comes to printing it really doesn't matter if you construct a string on the stack and pass it along. You're IO bound anyway.

By the by: if you or anyone is interested in swift's string interpolation design decisions (for inspiration or whatever) then here's the full discussion: https://forums.swift.org/t/string-interpolation-revamp-design-decisions/12624

One very interesting thing of note is the way they combine named arguments with string interpolations.

Also another note, this tuple expansion should really not be called string interpolation, since it does not result in a string :/ It's more string expansion really.
February 29, 2020
On Saturday, 29 February 2020 at 00:57:54 UTC, aliak wrote:
> Also another note, this tuple expansion should really not be called string interpolation, since it does not result in a string :/ It's more string expansion really.

Yeah, me and Steven agreed on this too in the other thread, and I thought I updated my DIP but I guess not.

wait a minute yes i did https://gist.github.com/adamdruppe/a58f097d974b364ae1cbc8c050dd9a3f

on the gist version, I called it "Formatted string tuple literals", but I never saved tht back to my local or github versions. oops.

But basically I see our new thing as being a string builder rather than a string per se.