Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Initializer Lists within Block initialization default to BLOCK! #1

Open
hostilefork opened this issue Dec 12, 2014 · 6 comments
Open

Comments

@hostilefork
Copy link
Member

Right now you have to write:

ren::Block {1, red::Block{2, 3}, 4}

Using a std::initializer_list, this could default to the behavior of assuming "brace means block". Then you could write:

ren::Block {1, {2, 3}, 4}

It's a little bit questionable because { isn't really a [, and there's not necessarily any real reason why a BLOCK! should get this special treatment over PAREN! or PATH!. But it might be cute.

@hostilefork
Copy link
Member Author

Talking to myself again? I have a habit of doing this.

But it might be cute.

It might be. But bear in mind that punning on { } is dodgier than even that, because it doesn't mean "array" or "group" in C++ any more. It's the syntax used in uniform initialization. So you can write int foo {1020}; and no "blocks" are involved.

As it turns out, there is a technical reason not to do it also. The way AnyBlock uses variadic construction to get a memory-efficient std::array under the hood (vs. a std::vector) won't work with it.

Here's the mumbo-jumbo explaining why, via Nicol Bolas:

Uniform initialization does not work with forwarding. You can't forward initialization parameters (directly) and then use those to initialize some object. You can initialize a parameter of a function and then forward that along to someone else, but you can't forward initialization parameters.

Braced-init-lists (aka: the {} stuff) do not participate in template argument deduction.

I've done experiments showing it is possible to get the behavior if you move to an initializer_list based implementation. But that would take away the variadic construction that sets up the std::array, which is 100% just a C-style array under the hood. So that would allocate a vector on every such construction. Not that expensive, but a little bit of an expense. For the questionable payoff of ambiguous-looking code.

If you want to save on typing there's lots of ways to get that:

using BLK = ren::Block;

BLK{1, BLK{2, 3}, 4}

@hostilefork
Copy link
Member Author

Reopening this issue for discussion.

@Morwenn pointed out that the technical underpinnings of initializer_list were actually an array...and you could effectively get at the data for that array as a pointer from the iterator. So basically all the std::array work was not necessary.

This seems to reopen the door to this. I talked myself out of it partially from an implementation point of view, but maybe it should be rethought--so that if we can do it, should we?

@hostilefork
Copy link
Member Author

To truly close this issue out, @hostilefork needs to go back to the code review question and fix it up to correct potential future misunderstandings for others.

http://codereview.stackexchange.com/q/72252/9042

Old link from source about performance gap of vector vs. array:

http://stackoverflow.com/q/381621/211160

@Morwenn
Copy link
Contributor

Morwenn commented Jan 16, 2015

So, the problem should definitely be solved with the pull request #51 (as explained in its description). To sum up just in case we need to check again in the future:

  • AnyBlock_ has a third parameter BracesT which correspond to the type built by the curly braces when no type is specified.
  • This parameter defaults to void so that untyped curly braces are a compile time error if not explicitly specified otherwise.
  • Block provides Block as a third parameter so that it can easily create blocks of blocks with less typing.
  • Everything else uses the default void.

The global behaviour of untyped curly braces can then be trivially defined for every type deriving from AnyBlock_ and the default behaviour can also be trivially changed by changing the default value for the third template parameter of AnyBlock_. I do think that this resolution can solve almost any future issue related to Loadable and curly braces.

@hostilefork
Copy link
Member Author

So what's keeping this an open issue for now is that while the method is working for constructors, it's not working for variadic functions. So:

runtime(1, {2, 3}, 4);

Won't make a block out of {2, 3} even if you use BlockLoadable. @Morwenn says this is likely a technical limitation of constructors that take initializer lists vs. variadic functions that do. It may warrant a StackOverflow question for a canon answer.

If it turns out to be true that you can't do it, then it can either be left alone or some trick to make runtime calls somehow rig around internally with a class constructed on each call, so something like:

runtime {1, {2, 3}, 4};

Exactly what that would involve is not known. But this is a good thing to consider as the runtime/engine level goes under review.

@Morwenn
Copy link
Contributor

Morwenn commented Feb 2, 2015

The thing is that the only way to get as many elements as we want in operator() is to make it a variadic template, and variadic templates use the template deduction mechanism, which can't deduce an std::initializer_list, so we can't give meaning to untyped braces in this context. In order to do what we want with operator(), we would need a language extension so that we can write this:

template <std::size_t N>
void operator(BlockLoadable<Block>...[n] loadables)
{
    // the code
}

With such a anguage extension (proposed, but I am not even sure that it will make it to C++17), the compiler would know that every parameter is to be deduced as a BlockLoadable<Block>; there wouldn't the same template deduction mechanism. Unfortunately, it's unlikely that we will have this extension before long. Therefore, if we really want {} == Block {}, the constructor solution would be the more feasable one with some changes to how runtime is handled.

hostilefork pushed a commit that referenced this issue Feb 16, 2015
Detailed set up and build instructions for Linux
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants