Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-19 Thread Mark via Digitalmars-d-announce

On Friday, 18 January 2019 at 20:29:08 UTC, H. S. Teoh wrote:
That would work, but it would also suffer from all the same 
problems as macro-based programming in C.  The compiler would 
be unable to detect when you accidentally pasted type names 
together where you intended to be separate, the strings may not 
actually represent real types, and generating code from pasting 
/ manipulating strings is very error-prone. And you could write 
very unmaintainable code like pasting partial tokens together 
as strings, etc., which makes it hard for anyone else 
(including yourself after 3 months) to understand just what the 
code is trying to do.


Generally, you want some level of syntactic / semantic 
enforcement by the compiler when you manipulate lists (or 
whatever other structures) of types.



T


Well, it's the approach Andrei laid out in his DConf 2018 talk:
https://youtu.be/-0jcE9B5kjs?t=2641

The advantage is how simple it is, and that it only uses existing 
language constructs. But, indeed, the problems you mention are 
not insignificant.


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread Paul Backus via Digitalmars-d-announce

On Friday, 18 January 2019 at 20:03:48 UTC, Mark wrote:

[...]

Represent types as strings, CTFE them as you see fit, and 
output a string that can then be mixin'ed to use the actual 
type. :)


Two problems:

1) Mixing in a string is unhygienic. If two modules (or two 
scopes in the same module) define types with the same name, you 
might get the wrong one.


2) You can't mixin the name of a Voldemort type.


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread Stefan Koch via Digitalmars-d-announce

On Friday, 18 January 2019 at 20:32:35 UTC, Jacob Carlborg wrote:

On 2019-01-18 20:28, Stefan Koch wrote:

The only difference that type-functions have from what you 
describe is that it does not need to occupy a keyword 'type'.


You're using "alias" instead of my "type" keyword?


yes. After all what type-functions do when returning types,  is 
to return an alias.

Since it's unable to create types this is all it can do.


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread Jacob Carlborg via Digitalmars-d-announce

On 2019-01-18 20:28, Stefan Koch wrote:

The only difference that type-functions have from what you describe is 
that it does not need to occupy a keyword 'type'.


You're using "alias" instead of my "type" keyword?

--
/Jacob Carlborg


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread H. S. Teoh via Digitalmars-d-announce
On Fri, Jan 18, 2019 at 08:03:48PM +, Mark via Digitalmars-d-announce wrote:
[...]
> Why not do away with AliasSeq and use strings all the way?
> 
> string Constify(string type)
> {
> // can add input checks here
> return "const(" ~ type ~ ")";
> }
> 
> void main()
> {
> import std.algorithm : map;
> enum someTypes = ["int", "char", "bool"];
> enum constTypes = map!Constify(someTypes);
> mixin(constTypes[0] ~ "myConstInt = 42;"); // int myConstInt = 42;
> }
> 
> Represent types as strings, CTFE them as you see fit, and output a
> string that can then be mixin'ed to use the actual type. :)

That would work, but it would also suffer from all the same problems as
macro-based programming in C.  The compiler would be unable to detect
when you accidentally pasted type names together where you intended to
be separate, the strings may not actually represent real types, and
generating code from pasting / manipulating strings is very error-prone.
And you could write very unmaintainable code like pasting partial tokens
together as strings, etc., which makes it hard for anyone else
(including yourself after 3 months) to understand just what the code is
trying to do.

Generally, you want some level of syntactic / semantic enforcement by
the compiler when you manipulate lists (or whatever other structures) of
types.


T

-- 
INTEL = Only half of "intelligence".


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread Mark via Digitalmars-d-announce
On Thursday, 17 January 2019 at 20:47:38 UTC, Steven 
Schveighoffer wrote:


well, there was no static foreach for that article (which I 
admit I didn't read, but I know what you mean).


But it's DEFINITELY not as easy as it could be:

import std.conv;

alias AliasSeq(P...) = P;

template staticMap(alias Transform, Params...)
{
alias seq0 = Transform!(Params[0]);
static foreach(i; 1 .. Params.length)
{
   mixin("alias seq" ~ i.to!string ~ " = AliasSeq!(seq" ~ 
(i-1).to!string ~ ", Transform!(Params[" ~ i.to!string ~ 
"]));");

}
mixin("alias staticMap = seq" ~ (Params.length-1).to!string 
~ ";");

}

alias Constify(T) = const(T);
void main()
{
alias someTypes = AliasSeq!(int, char, bool);
pragma(msg, staticMap!(Constify, someTypes)); // 
(const(int), const(char), const(bool))

}

Note, that this would be a LOT easier with string 
interpolation...


mixin("alias seq${i} = AliasSeq!(seq${i-1}, 
Transform!(Params[${i}]));".text);


-Steve


Why not do away with AliasSeq and use strings all the way?

string Constify(string type)
{
// can add input checks here
return "const(" ~ type ~ ")";
}

void main()
{
import std.algorithm : map;
enum someTypes = ["int", "char", "bool"];
enum constTypes = map!Constify(someTypes);
mixin(constTypes[0] ~ "myConstInt = 42;"); // int myConstInt 
= 42;

}

Represent types as strings, CTFE them as you see fit, and output 
a string that can then be mixin'ed to use the actual type. :)


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread Stefan Koch via Digitalmars-d-announce

On Friday, 18 January 2019 at 10:23:11 UTC, Jacob Carlborg wrote:

On 2019-01-17 23:44, H. S. Teoh wrote:

YES!  This is the way it should be.  Type-tuples become first 
class
citizens, and you can pass them around to functions and return 
them from

functions
No no no, not only type-tuples, you want types to be first 
class citizens. This makes it possible to store a type in a 
variable, pass it to and return from functions. Instead of a 
type-tuple, you want a regular array of types. Then it would be 
possible to use the algorithms in std.algorithm to manipulate 
the arrays. I really hate that today one needs to resort to 
things like staticMap and staticIndexOf.


Of course, if we both get tuples and types as first class 
citizens it would be possible to store types in these tuples as 
well. But a tuple is usually immutable and I'm not sure if it 
would be possible to use std.algorithm on that.


It would be awesome to be able to do things like this:

type foo = int;

type bar(type t)
{
return t;
}

auto u = [byte, short, int, long].map!(t => t.unsigned).array;
assert(u == [ubyte, ushort, uint, ulong];


Yes, you will be able to do exactly what you describe above.
type-tuples are strictly a superset of types; which also include 
true compile-time constants. (e.g. things you can use to 
instantiate a template with.)


Within type functions you are able to create `alias[]` which is 
in some ways equivalent to type-tuple (and will be converted to 
one upon being returned outside of compile-functions),which you 
can append to if you own it and type functions can also take 
other type-functions as parameters.
Therefore it's perfectly possible to implement staticMap in terms 
of type functions.

I already did the semantic sanity checks, and it shows promise.

The only difference that type-functions have from what you 
describe is that it does not need to occupy a keyword 'type'.


Cheers,
Stefan


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread H. S. Teoh via Digitalmars-d-announce
On Fri, Jan 18, 2019 at 11:23:11AM +0100, Jacob Carlborg via 
Digitalmars-d-announce wrote:
> On 2019-01-17 23:44, H. S. Teoh wrote:
> 
> > YES!  This is the way it should be.  Type-tuples become first class
> > citizens, and you can pass them around to functions and return them
> > from functions
> No no no, not only type-tuples, you want types to be first class
> citizens.  This makes it possible to store a type in a variable, pass
> it to and return from functions. Instead of a type-tuple, you want a
> regular array of types.  Then it would be possible to use the
> algorithms in std.algorithm to manipulate the arrays. I really hate
> that today one needs to resort to things like staticMap and
> staticIndexOf.

Yes, that would be the next level of symmetry. :-D  Types as first class
citizens would eliminate another level of distinctions that leads to the
necessity of staticMap, et al.  But it will also require changing the
language in a much more fundamental, invasive way.

So I'd say, let's take it one step at a time.  Start with first-class
type-tuples, then once that's ironed out and working well, take it to
the next level and have first-class types.  Trying to leap from here to
there in one shot is probably a little too ambitious, with too high a
chance of failure.


[...]
> It would be awesome to be able to do things like this:
> 
> type foo = int;
> 
> type bar(type t)
> {
> return t;
> }
> 
> auto u = [byte, short, int, long].map!(t => t.unsigned).array;
> assert(u == [ubyte, ushort, uint, ulong];
[...]

Yes this would be awesome.  But in order to avoid unmanageable
complexity of implementation, all of this would have to be compile-time
only constructs.


T

-- 
Your inconsistency is the only consistent thing about you! -- KD


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread H. S. Teoh via Digitalmars-d-announce
On Thu, Jan 17, 2019 at 05:32:52PM -0800, Walter Bright via 
Digitalmars-d-announce wrote:
> On 1/17/2019 11:31 AM, H. S. Teoh wrote:
> > [...]
> 
> Thanks for the thoughtful and well-written piece.
> 
> But there is a counterpoint: symmetry in mathematics is one thing, but
> symmetry in human intuition is not. Anytime one is dealing in human
> interfaces, one runs into this.  I certainly did with the way imports
> worked in D. The lookups worked exactly the same for any sort of
> symbol lookup. I thought it was great.
> 
> But I was unable to explain it to others. Nobody could understand it
> when I said imported symbol lookup worked exactly like any lookup in a
> name space.  They universally said it was "unintuitive", filed bug
> reports, etc.  Eventually, I had to give it up. Now import lookup
> follows special different rules, people are happy, and I learned
> (again) that symmetry doesn't always produce the best outcomes.

Alas, it's true, it's true, 100% symmetry is, in the general case,
impossible to achieve.  If we wanted 100% mathematical symmetry, one
could argue lambda calculus is the best programming language ever,
because it's Turing complete, the syntax is completely uniform with no
quirky exceptions, and the semantics are very clearly defined with no
ambiguity anywhere.  Unfortunately, these very characteristics are also
what makes lambda calculus impossible to work with for anything but the
most trivial of programs. It's completely unmaintainable, extremely hard
to read, and has non-trivial semantics that vary wildly from the
smallest changes to the code.

For a human-friendly programming language, any symmetry must necessarily
be based on human expectations.  Unfortunately, as you learned, human
intuition varies from person to person, and indeed, is often
inconsistent even with the same person, so trying to maximise symmetry
in a way that doesn't become "counterintuitive" is a pretty tall order.

As somebody (perhaps you) said once, in Boeing's experience with
designing intuitive UIs, they discovered that what people consider
"intuitive" is partly colored by their experience, and their experience
is in turn shaped by the UIs they interact with.  So it's a feedback
loop, which means what's "intuitive" is not some static set of rules
(even allowing for arbitrarily complex rules), but it's a *moving
target*, the hardest thing to design for.  What's considered "intuitive"
today may be considered "totally counter-intuitive" 10 years from now.

In the case of imports, I'd argue that the problem is with how people
understand the word "import".  From a compiler's POV, the simplest, most
straightforward (and most symmetric!) definition is "pull in the symbols
into the local scope".  Unfortunately, that's not the understanding most
programmers have.  Perhaps in an older, bygone era people might have
been more open to that sort of definition, but in this day and age of
encapsulation and modularity, "pull in symbols into the local scope"
does not adequately capture people's expectations: it violates
encapsulation, in the following sense: symbols from the imported module
shadow local symbols, which goes against the expectation that the local
module is an encapsulated thing, inviolate from outside interference.
It breaks the expectation of encapsulation.  It breaks the symmetry that
everywhere else, outside code cannot interfere with local symbols.

Consequently, the expectation is that imported symbols are somehow
"second class" relative to local symbols -- imported symbols don't
shadow local symbols (unless you explicitly ask for it), and thus
encapsulation is preserved (in some sense).  So we have here a conflict
between different axes of symmetry: the symmetry of every module being
an inviolate, self-contained unit (encapsulation), and the symmetry of
having the same rules for symbol lookup no matter where the symbol came
from.  It's a toss-up which axis of symmetry one should strive for, and
which one should be compromised.

I'd say the general principle ought to be that the higher-level symmetry
(encapsulation of modules) should override the lower-level symmetry (the
mechanics of symbol lookup).  But this is easy to say because hindsight
is 20/20; it's not so simple at the time of decision-making because it's
not obvious which symmetries are in effect and what their relative
importance should be.  And there's always the bugbear that symmetry from
the implementor's (compiler writer's) POV does not necessarily translate
to symmetry from the user's (language user's) POV.

Still, I'd say that in a general sense, symmetry ought to be a
relatively high priority as far as designing language features or
adding/changing features are concerned.  Adding a new feature with
little regard for how it interacts with existing features, what new
corner cases it might introduce, etc., is generally a bad idea. Striving
for maximal symmetry should at least give you a ballpark idea for where
things should be headed, 

Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread Jacob Carlborg via Digitalmars-d-announce

On 2019-01-17 23:44, H. S. Teoh wrote:


Interesting.  Is it possible to assign a "fake" mangle to type functions
that never actually gets emitted into the object code, but just enough
to make various internal compiler stuff that needs to know the mangle
work properly?


Not sure that would be possible. I tries to a support for pragma(mangle) 
on alias declarations. That opened a can of worms. It turns out that the 
compiler is using the mangling of a type to compare types internally.


--
/Jacob Carlborg


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-18 Thread Jacob Carlborg via Digitalmars-d-announce

On 2019-01-17 23:44, H. S. Teoh wrote:


YES!  This is the way it should be.  Type-tuples become first class
citizens, and you can pass them around to functions and return them from
functions
No no no, not only type-tuples, you want types to be first class 
citizens. This makes it possible to store a type in a variable, pass it 
to and return from functions. Instead of a type-tuple, you want a 
regular array of types. Then it would be possible to use the algorithms 
in std.algorithm to manipulate the arrays. I really hate that today one 
needs to resort to things like staticMap and staticIndexOf.


Of course, if we both get tuples and types as first class citizens it 
would be possible to store types in these tuples as well. But a tuple is 
usually immutable and I'm not sure if it would be possible to use 
std.algorithm on that.


It would be awesome to be able to do things like this:

type foo = int;

type bar(type t)
{
return t;
}

auto u = [byte, short, int, long].map!(t => t.unsigned).array;
assert(u == [ubyte, ushort, uint, ulong];

--
/Jacob Carlborg


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread Walter Bright via Digitalmars-d-announce

On 1/17/2019 11:31 AM, H. S. Teoh wrote:

[...]


Thanks for the thoughtful and well-written piece.

But there is a counterpoint: symmetry in mathematics is one thing, but symmetry 
in human intuition is not. Anytime one is dealing in human interfaces, one runs 
into this. I certainly did with the way imports worked in D. The lookups worked 
exactly the same for any sort of symbol lookup. I thought it was great.


But I was unable to explain it to others. Nobody could understand it when I said 
imported symbol lookup worked exactly like any lookup in a name space. They 
universally said it was "unintuitive", filed bug reports, etc. Eventually, I had 
to give it up. Now import lookup follows special different rules, people are 
happy, and I learned (again) that symmetry doesn't always produce the best outcomes.


User interfaces (and programming languages certainly are user interfaces) are 
hard and (ironically) are anything but intuitive to design.


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread Walter Bright via Digitalmars-d-announce

On 1/17/2019 8:06 AM, bpr wrote:

Was that a pre C++11 version of C++, or a more modern one?


pre C++11


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread Stefan Koch via Digitalmars-d-announce

On Thursday, 17 January 2019 at 22:44:08 UTC, H. S. Teoh wrote:
On Thu, Jan 17, 2019 at 10:20:24PM +, Stefan Koch via 
Digitalmars-d-announce wrote:
P.S. There is one caveat: because of how type-functions work 
they cannot, you cannot create a non-anonymous symbol inside a 
type-function, because there is no way to infer a mangle.


You can however create an anonymous symbol and alias it inside 
a template body, which gives it a mangle and it can behave 
like a regular symbol.


Interesting.  Is it possible to assign a "fake" mangle to type 
functions that never actually gets emitted into the object 
code, but just enough to make various internal compiler stuff 
that needs to know the mangle work properly?


No this is not possible, a symbol which is only used at 
compile-time is actually really rare. Actually If the symbol is 
constrained to a compile-time only context (e.g. inside is() or 
taking the .sizeof) this problem does not arise, and it could be 
allowed.


Imagine you want to return a struct type  which has all the 
fields of a given base struct but adds a member.

module ct_helper;

alias f(alias baseT, alias newMemberType, string newMember_name)
{
   struct Extended
   {
   baseT base;
   mixin("newMemberType " ~ newMemberName);
   }
   return typeof(Extended.init);
}

--

module user

struct S1 { int x; }
alias S2 = f!(S1, float, "y") // looks like a 
template-instantiation but it's not!, I am just reusing it, to 
not confuse the parser to much.


which mangle should this get?
S2 ?  - doesn't work there is no mangle for an alias.
 ct_helper.f.Extended? doesn't work if we call the type-function 
again with diffrent arguments
make it an anonymous type ? - If we do that than this means that 
the type-function is no longer pure as two anonymous types can 
never Equal each other


include the arguments to the type-function and it's parameters in 
the mangle? - that's possible but type-functions are not meant to 
leave any sign of their existence in order to not introduce ABI 
issues.


In short for now I'd rather side-step the problem by not allowing 
freshly minted types to escape into a runtime context without 
going through a template wrapper (which also handles caching and 
has proper behavior in is-expressions).




Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread Johannes Loher via Digitalmars-d-announce
Am 17.01.19 um 23:20 schrieb Stefan Koch:
> For 2 years I have pondered this problem, and I did come up with a
> solution.
> It's actually not that hard to have CTFE interact with type-tuples.
> You can pass them as function parameters, or return them if you wish.
> Of course a type-tuple returning ctfe function, is compile-time only.
> This solved one more problem that ctfe has:
> helper functions required for ctfe can only be omitted from the binary,
> if you use the trick of putting them into a module which is the import
> path but never explicitly given on the command line.
> newCTFE has the facility to be extended for this, and implementing
> type-functions is at least on my personal roadmap.
> 
> At Dconf 2018 Andrei and Walter said, a DIP which is substantiated
> enough might make it.
> However due to lack of time, (and productivity-reducing internal
> changes) it will take some time until I can get started on this.
> 
> Also I plan for newCTFE to be in shape before I add type-manipulation
> abilities.
> 
> Cheers,
> 
> Stefan
> 
> P.S. There is one caveat: because of how type-functions work they
> cannot, you cannot create a non-anonymous symbol inside a type-function,
> because there is no way to infer a mangle.
> You can however create an anonymous symbol and alias it inside a
> template body, which gives it a mangle and it can behave like a regular
> symbol.
> 
> 
This is one of the most exciting things i have read in recent times!



Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread H. S. Teoh via Digitalmars-d-announce
On Thu, Jan 17, 2019 at 10:20:24PM +, Stefan Koch via 
Digitalmars-d-announce wrote:
> On Thursday, 17 January 2019 at 19:31:24 UTC, H. S. Teoh wrote:
[...]
> > Coming back to the D example at the end, I totally agree with the
> > sentiment that D templates, in spite of their significant
> > improvements over C++ syntax, ultimately still follow the same
> > recursive model. Yes, you can use CTFE to achieve the same thing at
> > runtime, but it's not the same thing, and CTFE cannot manipulate
> > template argument lists (aka AliasSeq aka whatever it is you call
> > them).  This lack of symmetry percolates down the entire template
> > system, leading to the necessity of the hack that Bartosz refers to.
> > 
> > Had template argument lists / AliasSeq been symmetric w.r.t. runtime
> > list manipulation, we would've been able to write a foreach loop
> > that manipulates the AliasSeq in the most readable way without
> > needing to resort to hacks or recursive templates.
> > 
> For 2 years I have pondered this problem, and I did come up with a
> solution.  It's actually not that hard to have CTFE interact with
> type-tuples.  You can pass them as function parameters, or return them
> if you wish.  Of course a type-tuple returning ctfe function, is
> compile-time only.

YES!  This is the way it should be.  Type-tuples become first class
citizens, and you can pass them around to functions and return them from
functions, the only stipulation being that they can only exist at
compile-time, so it's an error to use them at runtime.

In other words, they become symmetric to other built-in language types,
and can be manipulated by conventional means, instead of being an
oddball exception with special-case behaviour that requires special-case
syntax dedicated to manipulating them.  Again, the root of the problem
is asymmetry, and the solution is to make it symmetric.


> This solved one more problem that ctfe has:
> helper functions required for ctfe can only be omitted from the
> binary, if you use the trick of putting them into a module which is
> the import path but never explicitly given on the command line.

Exactly.  Yet another problem caused by the asymmetry of type-tuples
w.r.t. other built-in types, and naturally solved by making them
symmetric.


> newCTFE has the facility to be extended for this, and implementing
> type-functions is at least on my personal roadmap.

Awesome.


> At Dconf 2018 Andrei and Walter said, a DIP which is substantiated
> enough might make it.
> However due to lack of time, (and productivity-reducing internal
> changes) it will take some time until I can get started on this.
> 
> Also I plan for newCTFE to be in shape before I add type-manipulation
> abilities.

Yes, let's please get the Minimum Viable Product of newCTFE merged into
master first, before we expand the scope (and delay the schedule :-P)
yet again!


[...]
> P.S. There is one caveat: because of how type-functions work they
> cannot, you cannot create a non-anonymous symbol inside a
> type-function, because there is no way to infer a mangle.
>
> You can however create an anonymous symbol and alias it inside a
> template body, which gives it a mangle and it can behave like a
> regular symbol.

Interesting.  Is it possible to assign a "fake" mangle to type functions
that never actually gets emitted into the object code, but just enough
to make various internal compiler stuff that needs to know the mangle
work properly?


T

-- 
Why do conspiracy theories always come from the same people??


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread Stefan Koch via Digitalmars-d-announce

On Thursday, 17 January 2019 at 19:31:24 UTC, H. S. Teoh wrote:
On Thu, Jan 17, 2019 at 06:03:07PM +, Paul Backus via 
Digitalmars-d-announce wrote: [...]
[2] 
https://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/

[...]

Coming back to the D example at the end, I totally agree with 
the sentiment that D templates, in spite of their significant 
improvements over C++ syntax, ultimately still follow the same 
recursive model. Yes, you can use CTFE to achieve the same 
thing at runtime, but it's not the same thing, and CTFE cannot 
manipulate template argument lists (aka AliasSeq aka whatever 
it is you call them).  This lack of symmetry percolates down 
the entire template system, leading to the necessity of the 
hack that Bartosz refers to.


Had template argument lists / AliasSeq been symmetric w.r.t. 
runtime list manipulation, we would've been able to write a 
foreach loop that manipulates the AliasSeq in the most readable 
way without needing to resort to hacks or recursive templates.


For 2 years I have pondered this problem, and I did come up with 
a solution.
It's actually not that hard to have CTFE interact with 
type-tuples.
You can pass them as function parameters, or return them if you 
wish.
Of course a type-tuple returning ctfe function, is compile-time 
only.

This solved one more problem that ctfe has:
helper functions required for ctfe can only be omitted from the 
binary, if you use the trick of putting them into a module which 
is the import path but never explicitly given on the command line.
newCTFE has the facility to be extended for this, and 
implementing type-functions is at least on my personal roadmap.


At Dconf 2018 Andrei and Walter said, a DIP which is 
substantiated enough might make it.
However due to lack of time, (and productivity-reducing internal 
changes) it will take some time until I can get started on this.


Also I plan for newCTFE to be in shape before I add 
type-manipulation abilities.


Cheers,

Stefan

P.S. There is one caveat: because of how type-functions work they 
cannot, you cannot create a non-anonymous symbol inside a 
type-function, because there is no way to infer a mangle.
You can however create an anonymous symbol and alias it inside a 
template body, which gives it a mangle and it can behave like a 
regular symbol.





Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread Steven Schveighoffer via Digitalmars-d-announce

On 1/17/19 2:31 PM, H. S. Teoh wrote:

On Thu, Jan 17, 2019 at 06:03:07PM +, Paul Backus via 
Digitalmars-d-announce wrote:
[...]

[2]
https://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/

[...]

Haha, seems D did better than C++ in this respect, but not quite at the
level of Haskell.

The C++ example of a template that takes templates and arguments and
declares another template is a perfect example of why C++ template
syntax is utterly horrible for doing these sorts of things.

Coming back to the D example at the end, I totally agree with the
sentiment that D templates, in spite of their significant improvements
over C++ syntax, ultimately still follow the same recursive model. Yes,
you can use CTFE to achieve the same thing at runtime, but it's not the
same thing, and CTFE cannot manipulate template argument lists (aka
AliasSeq aka whatever it is you call them).  This lack of symmetry
percolates down the entire template system, leading to the necessity of
the hack that Bartosz refers to.

Had template argument lists / AliasSeq been symmetric w.r.t. runtime
list manipulation, we would've been able to write a foreach loop that
manipulates the AliasSeq in the most readable way without needing to
resort to hacks or recursive templates.


well, there was no static foreach for that article (which I admit I 
didn't read, but I know what you mean).


But it's DEFINITELY not as easy as it could be:

import std.conv;

alias AliasSeq(P...) = P;

template staticMap(alias Transform, Params...)
{
alias seq0 = Transform!(Params[0]);
static foreach(i; 1 .. Params.length)
{
   mixin("alias seq" ~ i.to!string ~ " = AliasSeq!(seq" ~ 
(i-1).to!string ~ ", Transform!(Params[" ~ i.to!string ~ "]));");

}
mixin("alias staticMap = seq" ~ (Params.length-1).to!string ~ ";");
}

alias Constify(T) = const(T);
void main()
{
alias someTypes = AliasSeq!(int, char, bool);
pragma(msg, staticMap!(Constify, someTypes)); // (const(int), 
const(char), const(bool))

}

Note, that this would be a LOT easier with string interpolation...

mixin("alias seq${i} = AliasSeq!(seq${i-1}, 
Transform!(Params[${i}]));".text);


-Steve


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread H. S. Teoh via Digitalmars-d-announce
On Thu, Jan 17, 2019 at 06:03:07PM +, Paul Backus via 
Digitalmars-d-announce wrote:
[...]
> [2]
> https://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/
[...]

Haha, seems D did better than C++ in this respect, but not quite at the
level of Haskell.

The C++ example of a template that takes templates and arguments and
declares another template is a perfect example of why C++ template
syntax is utterly horrible for doing these sorts of things.

Coming back to the D example at the end, I totally agree with the
sentiment that D templates, in spite of their significant improvements
over C++ syntax, ultimately still follow the same recursive model. Yes,
you can use CTFE to achieve the same thing at runtime, but it's not the
same thing, and CTFE cannot manipulate template argument lists (aka
AliasSeq aka whatever it is you call them).  This lack of symmetry
percolates down the entire template system, leading to the necessity of
the hack that Bartosz refers to.

Had template argument lists / AliasSeq been symmetric w.r.t. runtime
list manipulation, we would've been able to write a foreach loop that
manipulates the AliasSeq in the most readable way without needing to
resort to hacks or recursive templates.

//

Lately, as I've been pondering over these fundamental language design
issues, I've become more and more convinced that symmetry is the way to
go.  And by symmetry, I mean the mathematical sense of being "the same
under some given mapping (i.e., transformation or substitution)".

Why is C++ template syntax such a mess to work with?  Because it's a
separate set of syntax and idioms grafted onto the original core
language with little or no symmetry between them.  Where the core
language uses < and > as comparison operators, template syntax uses <
and > as delimiters. This asymmetry leads to all kinds of nastiness,
like earlier versions of C++ being unable to parse
`templateA>` properly (the >> gets wrongly lexed as a
bitshift operator). An intervening space is required to work around this
asymmetry.  This is just one trivial example.

A more fundamental example, which also afflicts D, is that the template
instantiation mechanism is inherently recursive rather than iterative,
so when you need to write a loop, you have to paraphrase it as a
recursive template. This is asymmetric with the runtime part of the
language, where constructs like `foreach` are readily available to
express the desired semantics.

On a different note, the same principle of symmetry applies to built-in
types vs. user-defined types. In TDPL Andrei alludes to programmers
disliking built-in types having "magic" behaviour that's different from
user-defined types.  Why the dislike? Because of asymmetry. Built-in
types have special behaviour that cannot be duplicated by user-defined
types, so when you want the special behaviour but built-in types don't
quite meet your needs, you find yourself without any recourse. It is
frustrating because the reasoning goes "if built-in type X can have
magic behaviour B, why can't user-defined type Y have behaviour B too?"
The desire for behaviour B to be possible both for built-in types and
user-defined types stems from the desire for symmetry.

Why is alias this so powerful?  Because it lets a new type Y behave as
if it were an existing type X -- it's symmetry.  Similarly, the Liskov
Substitution Principle is essentially a statement of symmetry in the
universe of OO polymorphism.

Why is the Unix "everything is a file" abstraction so useful? Because of
symmetry: whether it's a physical file, a network socket, or pipe, it
exposes the same API. Code that works with the data don't have to care
about what kind of object it is; it can simply use the API that is
symmetric across different types of objects.

Similarly, why are D ranges so powerful? Because they make containers,
data sources, data generators, etc., symmetric under the range API
operations.  It allows code to be decoupled from the details of the
concrete types, and focus directly on the problem domain.

Why does the GC simplify many programming tasks so much? Because it
makes every memory-allocated object symmetric w.r.t. memory management:
you stop worrying about whether something is stack-allocated or
heap-allocated, whether it has cycles, or whether somebody else still
holds a reference to it -- you focus on the problem domain and let the
GC do its job.

At a higher level: in the old days, programming languages used to
distinguish between functions and procedures (and maybe some languages
still do, but they seem rare these days). But eventually this
distinction was ditched in favor of things like returning `void` (C,
C++, Java, D), or some other equivalent construct. Why? So that instead
of having two similar but asymmetric units of code encapsulation,
everything is just a "function" (it just so happens some functions don't
return a meaningful value). IOW, introduce symmetry, get rid of the
asymmetry.


On the flip side, 

Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread Paul Backus via Digitalmars-d-announce

On Thursday, 17 January 2019 at 16:06:39 UTC, bpr wrote:
On Thursday, 17 January 2019 at 01:59:29 UTC, Walter Bright 
wrote:
Bartosz Milewski is a C++ programmer and a Haskell fan. He 
once gave a presentation at NWCPP where he wrote a few lines 
of Haskell code. Then, he showed the same code written using 
C++ template metaprogramming.


The Haskell bits in the C++ code were highlighted in red. It 
was like a sea of grass with a shrubbery here and there. 
Interestingly, by comparing the red dots in the C++ code with 
the Haskell code, you could understand what the C++ was doing. 
Without the red highlighting, it was a hopeless wall of < > :-)


Was that a pre C++11 version of C++, or a more modern one?

It would be instructive to see that example with C++17 or even 
20 and D

next to each other.


The presentation was given at BoostCon 2011, and is (at least 
partially) available on youtube [1]. There is also a blog post 
from 2009, "What Does Haskell Have to Do with C++?" [2] that uses 
the same format, and presumably covers the same material. The 
examples in the blog post were tested with "the GNU C++ compiler 
v. 4.4.1 with the special switch -std=c++0x", which according to 
the GCC documentation [3] includes many (but not all) features 
from C++11.


[1] https://www.youtube.com/watch?v=GjhsSzRtTGY
[2] 
https://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/

[3] https://gcc.gnu.org/gcc-4.4/cxx0x_status.html


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread bpr via Digitalmars-d-announce

On Thursday, 17 January 2019 at 01:59:29 UTC, Walter Bright wrote:

On 1/16/2019 4:19 PM, H. S. Teoh wrote:
On Wed, Jan 16, 2019 at 11:43:19PM +, John Carter via 
Digitalmars-d-announce wrote:

[...]


Yes, that's one of the outstanding qualities of D, and one 
that I was
immensely impressed with when I perused the Phobos source code 
for the

first time.
Bartosz Milewski is a C++ programmer and a Haskell fan. He once 
gave a presentation at NWCPP where he wrote a few lines of 
Haskell code. Then, he showed the same code written using C++ 
template metaprogramming.


The Haskell bits in the C++ code were highlighted in red. It 
was like a sea of grass with a shrubbery here and there. 
Interestingly, by comparing the red dots in the C++ code with 
the Haskell code, you could understand what the C++ was doing. 
Without the red highlighting, it was a hopeless wall of < > :-)


Was that a pre C++11 version of C++, or a more modern one?

It would be instructive to see that example with C++17 or even 20 
and D

next to each other.


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-17 Thread H. S. Teoh via Digitalmars-d-announce
On Wed, Jan 16, 2019 at 05:59:29PM -0800, Walter Bright via 
Digitalmars-d-announce wrote:
[...]
> Bartosz Milewski is a C++ programmer and a Haskell fan. He once gave a
> presentation at NWCPP where he wrote a few lines of Haskell code.
> Then, he showed the same code written using C++ template
> metaprogramming.
> 
> The Haskell bits in the C++ code were highlighted in red. It was like
> a sea of grass with a shrubbery here and there. Interestingly, by
> comparing the red dots in the C++ code with the Haskell code, you
> could understand what the C++ was doing. Without the red highlighting,
> it was a hopeless wall of < > :-)
[...]

I don't know Haskell, but I've worked with Scheme (another Lisp dialect
/ derivative) a little, and sometimes I feel like the core of my logic
is little bits of shrubbery lost in an ocean of parentheses. :-P


T

-- 
I don't trust computers, I've spent too long programming to think that they can 
get anything right. -- James Miller


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-16 Thread Meta via Digitalmars-d-announce

On Thursday, 17 January 2019 at 01:59:29 UTC, Walter Bright wrote:
Bartosz Milewski is a C++ programmer and a Haskell fan. He once 
gave a presentation at NWCPP where he wrote a few lines of 
Haskell code. Then, he showed the same code written using C++ 
template metaprogramming.


The Haskell bits in the C++ code were highlighted in red. It 
was like a sea of grass with a shrubbery here and there. 
Interestingly, by comparing the red dots in the C++ code with 
the Haskell code, you could understand what the C++ was doing. 
Without the red highlighting, it was a hopeless wall of < > :-)


Since I mention Bartosz, I should link to his blog:

https://bartoszmilewski.com/


It was an article on Bartosz's blog where I first found out about 
D. I think this was the first one:


"The more things change, the more we need “immutable”"
https://bartoszmilewski.com/2009/01/


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-16 Thread Walter Bright via Digitalmars-d-announce

On 1/16/2019 4:19 PM, H. S. Teoh wrote:

On Wed, Jan 16, 2019 at 11:43:19PM +, John Carter via 
Digitalmars-d-announce wrote:

...I do find it remarkable that I can read the d code quite easily
without reaching for the reference manual, but to make sense of his
C++, it sends me trawling around cppreference.com


Yes, that's one of the outstanding qualities of D, and one that I was
immensely impressed with when I perused the Phobos source code for the
first time.
Bartosz Milewski is a C++ programmer and a Haskell fan. He once gave a 
presentation at NWCPP where he wrote a few lines of Haskell code. Then, he 
showed the same code written using C++ template metaprogramming.


The Haskell bits in the C++ code were highlighted in red. It was like a sea of 
grass with a shrubbery here and there. Interestingly, by comparing the red dots 
in the C++ code with the Haskell code, you could understand what the C++ was 
doing. Without the red highlighting, it was a hopeless wall of < > :-)


Since I mention Bartosz, I should link to his blog:

https://bartoszmilewski.com/


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-16 Thread Walter Bright via Digitalmars-d-announce

On 1/16/2019 3:43 PM, John Carter wrote:

Somebody on the C++ side has written a reply

https://brevzin.github.io/c++/2019/01/15/if-constexpr-isnt-broken/


From the article:

D (with corrections):

  static if (maxLength < 0xFFFE) {
alias CellIdx = uint16_t;
  } else {
alias CellIdx = uint32_t;
  }

C++:

  static constexpr auto get_type() {
if constexpr (maxLength < 0xFFFE) {
return type;
} else {
return type;
}
  }

  using CellIdx = decltype(get_type())::type;

1. you've got to write a function separately for every declaration you want to 
declare in a conditional. Imagine doing 4 or 5 of these.


2. imagine this:

static if (condition)
  int x;
...
static if (condition)
  ++x;

The C++ idiom would require (along with creating another function) creating a 
dummy x declaration for the (omitted) else branch of the static if.
Doable, but ugly. It kinda reminds me of the C diehards who showed you can write 
virtual function dispatch in C.


It's remarkable that these things can be done in C++, but the amount of "noise" 
and "boilerplate" in the solutions make them pretty hard to read.


Re: B Revzin - if const expr isn't broken (was Re: My Meeting C++ Keynote video is now available)

2019-01-16 Thread H. S. Teoh via Digitalmars-d-announce
On Wed, Jan 16, 2019 at 11:43:19PM +, John Carter via 
Digitalmars-d-announce wrote:
[...]
> Given that I have probably written a lot more C++ code in my life than
> d...
> 
> ...I do find it remarkable that I can read the d code quite easily
> without reaching for the reference manual, but to make sense of his
> C++, it sends me trawling around cppreference.com

Yes, that's one of the outstanding qualities of D, and one that I was
immensely impressed with when I perused the Phobos source code for the
first time.  After having (tried to) read glibc's source code (if you
never have, I advise you not to unless you're a jaded, hardened,
hardcore C professional -- it's *not* for the faint of heart), it was
like a breath of fresh air.  D does have its warts and dark corners, but
I think on the readability front it has scored a home run compared to
the equivalent C/C++ code.


> I find Andrei's claim that checkint with a void hook reverts to int is
> amazing, and would love to verify that at the assembly level for both
> the C++ and d implementations.

This is actually quite trivial in D.  I'm too lazy to actually check the
checkedint source code, but I'd surmise it's something as simple as:

template CheckedInt(alias hook) {
static if (is(typeof(hook) == void))
alias CheckedInt = int;
else {
struct CheckedInt {
... // actual CheckedInt implementation here
}
}
}

or something along these lines.  Standard D practice.  (I daren't even
try to imagine what I'd have to do to make this work in C++. After
having worked with C++ for about 2 decades or so, I don't have many good
things to say about it, nor do I expect very much from it anymore.)


T

-- 
Windows 95 was a joke, and Windows 98 was the punchline.