December 24, 2013
On Mon, Dec 23, 2013 at 04:30:14PM -0800, Andrei Alexandrescu wrote:
> On 12/23/13 5:41 AM, Maxim Fomin wrote:
> >Personally I am upset when I get some weird Phobos structure which simulates language feature, rathen then having feature in the language in first place.
> 
> It's a fine line to thread.

<grammarnazi> *tread. </grammarnazi>


> Erring on either side is easy and with bad consequences.
[...]

Personally, I'm for simplifying the core language and moving non-essentials out to the standard library -- *provided* that said standard library feature (1) doesn't suffer from overly ugly syntax due to not being part of the language proper, and (2) isn't defective in functionality in some way that a built-in wouldn't be.

Building too many things into the language is bad because it makes the
language (1) more complex than it needs to be, (2) harder to learn as a
result, and (3) require way too much effort to implement (or implement
*correctly*)(*cough*C++*cough*) -- you end up with "language is defined
by quirky compiler behaviour" rather than "language follows spec".


T

-- 
I think the conspiracy theorists are out to get us...
December 24, 2013
Andrei Alexandrescu:

> I don't think "various situations" is a good idea. It often does make code shorter. But it means more rules to be defined, implemented, and taught.

Here I have written "various situations" because I have given a list of those "various situations" in past posts.
I think the semantics is sufficiently natural, simple, and it's same for all those cases. I think the main problem in D is syntactic.


> It often does make code shorter.

It also avoids the programmer to think about useless details, leaving more brain for more important things. Assigning the fields to variables like this:

const uselessTmp = foo();
immutable something = uselessTmp[0];
immutable secondThing = uselessTmp[1];
const theLast = uselessTmp[2];

is as efficient as leaving that to the compiler.

Bye,
bearophile
December 24, 2013
H. S. Teoh:

> Personally, I'm for simplifying the core language and moving
> non-essentials out to the standard library

How do you define "essential"?
- Frequently used;
- The compiler can compile it as efficiently as handwritten code;
- Has a sufficiently clean semantics, that is most times the one that's desired;
- You can't (yet) implement its main purposes with library-code;
- Sufficiently important.
- etc.

Bye,
bearophile
December 24, 2013
On Tue, Dec 24, 2013 at 01:05:26AM +0000, bearophile wrote:
> H. S. Teoh:
> 
> >Personally, I'm for simplifying the core language and moving non-essentials out to the standard library
> 
> How do you define "essential"?
> - Frequently used;

I don't think 'frequently used' is sufficient to justify putting it in
the core language. If a library type (1) provides the same
functionality, (2) compiles to equally-efficient code, and (3) isn't
overly ugly to write, then I'd go with the library type.

For core language features, I consider orthogonality much more important. That is, if existing features can already do what the prospective feature can do, then it's probably better to put it in the standard library. A good candidate for inclusion in the core language is a feature that, if it were not in the language, would cause some things to be impossible to achieve (or to be achievable only with difficulty).

Ideally, the core language should be as minimalistic as possible, and provide only the truly essential features that the standard library can build on. There are a lot of advantages of a small core language: easier to implement, so more likely to be bug-free; reduction of the combinatorial explosion of features that introduce many hiding places for bugs / unexpected interactions because there are too many combinations of features to test; easier to reason about; etc.. Of course, in practice you can't be overly minimalistic, otherwise it becomes painful to do simple things; the adage is, "simple things should be easy, hard things should be possible".


> - The compiler can compile it as efficiently as handwritten code;

If the library implementation can be equally efficient, then this isn't a good reason to push the feature into the core language.


> - Has a sufficiently clean semantics, that is most times the one that's desired;

But isn't this an issue with in-compiler implementations too? An ill-defined feature is an ill-defined feature, no matter whether it's implemented in the library or the compiler.

Though I agree that if a compiler implementation has cleaner semantics than a library implementation, then the compiler implementation would be preferable.


> - You can't (yet) implement its main purposes with library-code;

This is a big reason to extend the core language, although even in this case I'd rather add only a minimal extension (not necessarily the entire feature) that makes it possible for library code to implement the feature, then put the actual implementation in the library.


> - Sufficiently important.
[...]

Important as measured by what? Important features can be part of the standard library too -- that's why it's the *standard* library, after all. It's a different story, of course, if said feature can't be adequately implemented by the library, but that's nothing to do with its importance, rather it's just a matter of extending the core language just enough to be able to implement it properly. Importance doesn't necessarily dictate that the feature must be implemented in the core language in its entirety.


T

-- 
INTEL = Only half of "intelligence".
December 24, 2013
I think this is just getting absurd.

The conflation between the naming issue and auto-expansion is so bloody dishonest. The DIP looks really good to newbies because it addresses the former but then they don't really understand the latter (as some have even said explicitly). Further, if this DIP had been discussed in *public* earlier, we could've handled this then, which could've resulted in an earlier resolution of the naming issue. I was genuinely wondering what was holding up the situation. Sigh.

The most important thing here is that std.typecons.Tuple is (conceptually) completely unrelated to std.typetuple.TypeTuple and other cases of the "tuple" name used to refer to template argument lists. This fact, compounded with insufficient and confusing documentation, causes the difficulty of learning. We can easily rectify this situation without any significant overhaul of Phobos' utility templates, which are mostly good as it is.

Then there is the separate issue of non-auto-expanding lists, necessary for algorithms that take a variadic number of variadic lists *that can contain types*[1]. I've been writing pretty heavy meta-programming code using template argument lists extensively since D1, and I've never required such an algorithm[2]. I've also taught new D programmers about template argument lists for years on IRC (including Dicebot), which is why I feel so strongly about the naming issue.

So, we're proposing that we cause this massive, non-trivial code breakage for the benefit of *who*, exactly? I have a feeling that if this is pushed through, disgruntled programmers who regard auto-expansion amicably will define their own substitutes for the previous infrastructure, which is much nicer to work with than the one proposed by this DIP, and much more in tune with the underlying language feature, *that people will still have to learn about*.

If a case for "packed lists" can be made, please make it separately.

[1] The distinction is necessary, because if only non-types are involved, CTFE + toTypeTuple(-ish) templates solves it, often very nicely.

[2] That's not to say that I think they don't exist - I know they do; but they are extremely niche. On the other hand, requiring a *fixed* number of variadic lists pops up now and then, and is trivially accomplished by using nested templates.
December 24, 2013
On Tue, Dec 24, 2013 at 02:52:18AM +0000, Jakob Ovrum wrote:
> I think this is just getting absurd.
> 
> The conflation between the naming issue and auto-expansion is so bloody dishonest. The DIP looks really good to newbies because it addresses the former but then they don't really understand the latter (as some have even said explicitly). Further, if this DIP had been discussed in *public* earlier, we could've handled this then, which could've resulted in an earlier resolution of the naming issue. I was genuinely wondering what was holding up the situation. Sigh.
> 
> The most important thing here is that std.typecons.Tuple is (conceptually) completely unrelated to std.typetuple.TypeTuple and other cases of the "tuple" name used to refer to template argument lists. This fact, compounded with insufficient and confusing documentation, causes the difficulty of learning. We can easily rectify this situation without any significant overhaul of Phobos' utility templates, which are mostly good as it is.
[...]

So if we only implemented the first part of the DIP, the renaming of std.typeconds.TypeTuple -> std.meta.list (or whatever, let's not start bikeshedding this early), along with the documentation cleanup which is long overdue anyway, would that be more acceptable to you?

As far as the auto-expand vs. non-auto-expand issue is concerned, I'm not sure why this is such a big deal.  I *have* run into cases where I needed one in some cases and the other in other cases. I solved the problem by simply wrapping stuff I didn't want to auto-expand in a non-eponymous template:

	template SubArgs(T...)
	{
		alias expand = T;
	}

	template NeedsNestedArgs(T...)
	{
		... // make use of T[0].expand
		... // make use of T[1].expand
		... // etc.
	}

	alias Instantiation = NeedsNestedArgs!(
		SubArgs!(...),
		SubArgs!(...), // will not merge with first list
		... // etc.
	);

Unless I'm missing the elephant in the room, both the auto-expanding and non-auto-expanding template arg lists can be implemented by a 3-line template declaration each (or 1 line if you use the new parametrized alias syntax). Which anyone can (re)write in 1 minute. So why is this such a big deal? Because of standardization? If that's the issue, then the non-auto-expanding version wins, because you can always turn it into an auto-expanding list with .expand, but if you're given an auto-expanding list you have to explicitly wrap it to stop it from expanding when it shouldn't. Which requires users to reinvent their own wrappers, which defeats the purpose of standardization.

Another win for non-auto-expanding is if the lists returned by std.traits.* et al are non-expanding by default, then you can pass them straight to another template as arguments without needing to worry about them flattening and merging where they aren't supposed to. Again, if you *want* to concatenate those lists, you can just use .expand (which also has the advantage of self-documenting exactly what is wanted -- the normal expectation is that separate arguments don't magically flatten out on you -- unless you're thinking of Perl lists -- so it makes sense to make expansion explicit).  Going the other way requires that *every* returned list be explicitly wrapped with a custom wrapper, which seems to be putting the weight on the wrong side of the boat. Is it really *that* common to want your lists auto-expanded by default?

Or am I missing something obvious here?


T

-- 
A mathematician is a device for turning coffee into theorems. -- P. Erdos
December 24, 2013
On Tuesday, 24 December 2013 at 04:08:25 UTC, H. S. Teoh wrote:

> So if we only implemented the first part of the DIP, the renaming of
> std.typeconds.TypeTuple -> std.meta.list (or whatever, let's not start
> bikeshedding this early), along with the documentation cleanup which is
> long overdue anyway, would that be more acceptable to you?

Yes, that's exactly what I've been arguing for since forever!

> Which requires users to reinvent their own
> wrappers, which defeats the purpose of standardization.

We should have both[1], with the auto-expanding one being the most commonly required.

> Is it really *that* common to want your lists
> auto-expanded by default?

Yes, it is. It's a natural consequence of how the language feature works.

At the end of the line, after being passed around to other templates for processing (discussed below), use of template argument lists boil down to several scenarios:

* Use for declaring an expression list from a type list, e.g. in a function parameter list or for fields in an aggregate. Requires expansion.

* Use for initalizing other expressions lists with an expression list, e.g. passing an expression list as arguments in a function call or in an array literal. Requires expansion.

* Use in static foreach. Requires expansion.

* Use in special expressions that operate on types, such as `is`, `typeof` and `typeid`. Requires expansion.

* Use as a public alias in a library interface, leaving the specifics of application to the user (but it always boils down to the above scenarios). Equal for both behaviours.

(Some but not all of the above might be equalized by Timon Gehr's AliasThis suggestion, but this remains to be proven)

Further, there is the issue of the processing itself - passing lists to algorithms receiving lists. If all of Phobos' list algorithms are rewritten to expect non-expanding lists, usage remains the same, for the *extremely* niche benefit of supporting a specific kind of variadic algorithm with the same kind of list. That's a whole lot of work for a whole lot of nothing.

Hence, I think this DIP is nothing but absurd. Excuse the strong language but I'm upset that it has caused a delay in the overdue renaming issue.

[1] Assuming that the case for non-auto-expanding lists can be argued sufficiently for inclusion in Phobos, which is yet to be seen. This DIP doesn't seem to even try.

P.S. I too like the name `list` to replace the current `TypeTuple`. The capitalization is correct with the new Phobos rules for list algorithms, and the succinctness respects how commonly used the template is.
December 24, 2013
On Tuesday, 24 December 2013 at 04:48:57 UTC, Jakob Ovrum wrote:
> [1] Assuming that the case for non-auto-expanding lists can be argued sufficiently for inclusion in Phobos, which is yet to be seen. This DIP doesn't seem to even try.

Clarification: "Assuming that the case for non-auto-expanding lists can be
> argued sufficiently for inclusion in Phobos, in the context of list algorithms that take a variadic number of variadic lists as arguments."

I feel that non-expanding lists only make sense in the context of these niche algorithms for the reasons explained in the parent post, and thus do not warrant conflation with auto-expanding lists.
December 24, 2013
On 12/23/13 7:34 AM, monarch_dodra wrote:
> My issue about this is that it will break existing code that doesn't
> even use the type "TypeTuple". What are the gains of:
>
> anySatisfy!(someTrait, TemplateArgumentList!(int, double));
> over
> anySatisfy!(someTrait, int, double)
>
> Or
>
> anySatisfy!(someTrait, TemplateArgumentList!(Args));
> over
> anySatisfy!(someTrait, Args)

Dicebot, are you proposing this? It has smell.


Andrei

December 24, 2013
On 12/23/13 8:21 AM, monarch_dodra wrote:
> On Monday, 23 December 2013 at 15:59:10 UTC, Timon Gehr wrote:
>> As is the former. :P
>> http://dlang.org/template.html#TemplateArgumentList
>>
>>
>> I think using the name TemplateArgumentList for anything other than a
>> shallow wrapper around a template argument list does not actually
>> improve the naming situation.
>
> This too also bothers me. I'd be more comfortable with (the even longer):
> "PackedTemplateArgumentList".

TemplateArgumentPack

Andrei