C++ Logo


Advanced search

Subject: Re: Making the new expression smart
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2020-09-18 08:07:22


I fear that we are one exchange away from the usual path in C++ related
discussions towards seeking confrontation for its own sake. It's a
lamentable feature of the C++ maintenance and standards community.

Nevertheless, in case I am wrong, some answers inline

On Fri, 18 Sep 2020 at 14:00, Ville Voutilainen <ville.voutilainen_at_[hidden]>

> On Fri, 18 Sep 2020 at 14:27, Richard Hodges via Std-Discussion
> <std-discussion_at_[hidden]> wrote:
> >> Interesting consistency, considering that &bar means address of bar
> >> everywhere else, but reference to bar
> >> in lambda captures.
> > & means "reference to" in argument declarations, method declarations,
> lambda captures and structured bindings.
> But not in any other variable declarations like the tuple examples you
> posted, except for variables involving lambdas.

and structured bindings

> > As for the confusion due to the use of & to also mean "address of", I
> would have to refer you to Mssrs Stroustrup, Kernighan, Ritchie et.al.
> for a rationale. I confess it was before my time. I've only been writing
> C++ since '98.
> I fail to see what this has to do with anything. I've only been
> writing C++ since '94. So what?
> >> > Performance:
> >> > Expression through library templates means two levels of translation
> of intent. One from user intent to expression in terms of existing library
> code and (sparse) core language features. There is plenty of opportunity
> for missing concepts in the language to limit the quality of that
> translation.
> >> > On the other hand, a keyword with code generation behind it means
> that a users’ specific intent can be translated into optimal code every
> time. Furthermore, as compiler technology improves, that translation can be
> improved, improving every program upon recompilation.
> >> > Of course this is partially true of libraries, but the library still
> suffers from not having access to direct code generation with knowledge of
> the absolute intent of the programmer.
> >>
> >> I don't quite see what the "plenty of opportunity for missing concepts
> >> in the language" might be, and how
> >> make_unique leads into any less-optimized code than writing the same
> >> with operators and sigils does.
> >
> >
> > I was under the impression that you were asking about my general
> rationale for preferring the creation of keywords to describe common
> concepts in the language rather than library types. It might be that I
> misunderstood. If you did mean what I thought you meant, then focusing on
> specific operations where there is no specific performance benefit
> immediately obvious today would seem to be to be confrontational. I will
> put it down to a misunderstanding.
> Well, you expressed a general preference that I thought applies to
> make_unique as opposed to a hypothetical new (unique).
> I point out that I don't see how some reasons for that general
> preference apply to make_unique. If you find that confrontational,
> that's not my problem.
> >> Things like tuple and make_unique don't rely on intrinsics. Wrt. "why
> >> bother with the complication of a library?", why bother
> >> with the complication of every compiler?
> > Again, std::tuple may or may not rely on intrinsics today, that is not
> the point. We know that a growing number of library constructs do.
> We do? Do you have examples?

An example was given below, of std::vector. You addressed this example and
demonstrated clear knowledge of it, so asking "we do?" as if incredulous is
actually disingenuous. It seems to me to be inviting a confrontation that I
am not seeking.

> > Why bother the compiler writer? Because compilers are few and
> programmers are many, so embedding best practice into the implementation of
> the compiler seems to me to provide best bang for buck in terms of
> disseminating excellence when transforming human intent into machine
> instructions. In addition, the compiler has the best possible view of the
> situation and is therefore the most informed agent in the compilation chain.
> I find it rather vague how "the compiler has the best possible view of
> the situation" when it has exactly the same view
> through library code in a library template.

When a problem is expressed through library code, the problem must first be
transcribed in terms of the library API, which is then transcribed by the
compiler into machine instructions (I appreciate that this is a simplistic
description of events). Thus the compiler's view of the user's use of (say)
a tuple is not "a view of a tuple, with all that that entails". It is a
view of some arbitrarily named struct/union with some code that has been
carefully crafted to provide the best possible utility of the concept of a
tuple that the library and language limitations allow.

This actually puts the compiler an extra translation step away from the
user's intent, and means that the intent cannot be perfectly expressed to
the code generator - information is lost in each step.

If a tuple were a language feature, there would be nothing lost in
translation. The compiler would understand intent because it is codified
into the object's interface.

A string or vector even more so, because the compiler would be able to make
assumptions about use and intent in many cases. It has taken until c++20
for string and vector to be constexpr (in theory) precisely because they
were expressed in terms of a library function that was not. If they were
not expressed in terms of any library feature at all and all in the
compiler, constant folding would have been possible prior to malloc being
made constexpr.

unordered_map still can't be constant-folded. Again, if it were a language
type, opportunities for internal optimisation would increase. Source code
could also be expressed more succinctly, since there would be no need for
convoluted template-based workarounds.

e.g. in the following hypothetical code:

  constexpr auto m = hash_map { { "foo" , 1 }, { "bar", 2 } };

  //use m

} // goes out of scope

it would be much more likely that a compiler could deduce intent based on
language rules rather than what amounts to a library-based workaround.
Furthermore, in that particular case the hash function could,as an
implementation QOL improvement, be optimised at compile time to be a
perfect hash. Performing this as part of a library solution is not trivial.
I am sure perfect hashed lookup through template logic is solved somewhere,
but expressing the templates in source code to produce it is beyond the
ability of most C++ developers.

> > A few years ago, I remember that there were laments about it being
> "impossible to implement std::vector with compliant code". One answer to
> that (the approach taken) is to supply library tools (backed by compiler
> intrinsics in the case of clang I believe). Another is to simply accept
> that vector is so useful and necessary a noun that it ought to be part of
> the language.
> The reason for supplying the library tools is that the problem wasn't
> vector-specific, it was more general than that,
> including problems with how std::allocator allocates a buffer for any
> contiguous container.

It transpires that you are acutely aware of (probably every) example of
solving library/compiler interop with intrinsics.

> > I appreciate that positions such as this have a tendency to ignite
> religious wars in the C++ community. You don't have to agree, but if you
> are going to engage with me I would ask that you consider the entirety of
> what I write, and understand that it is written in good faith.
> I fail to see what your complaint here is.

Richard Hodges
office: +442032898513
home: +376841522
mobile: +376380212

STD-DISCUSSION list run by std-discussion-owner@lists.isocpp.org

Older Archives on Google Groups