These are chat archives for boostorg/hana

20th
Jul 2016
Jonas Platte
@jplatte
Jul 20 2016 16:08
If I have a type-level predicate pred and a tuple of values xs, how can I make filter(xs, pred) work – that is, create a tuple of the values in xs of which the type satisfies pred?
Do I have to write a pred_v that operates on T const& instead of basic_type<T> const& or is there a better way?
Jason Rice
@ricejasonf
Jul 20 2016 16:33
The predicate has to be a "callable" object and take a single parameter. If you are working with types then I still recommend making a trait and lifting it with hana::trait.
Jonas Platte
@jplatte
Jul 20 2016 16:41
I'm not sure I follow.. By "trait" you mean normal C++ type-level functions as found in <type_traits>, right? And hana::trait seems to create an actual function operating on hana::basic_types from one of those traits. But what I want is a function that operates on values, so I can use it as the predicate when filtering a tuple of values.
Jason Rice
@ricejasonf
Jul 20 2016 16:43
If your values are hana::types then you can use traits or metafunctions. A trait returns a bool_c and a metafunction returns a type_c.
Jonas Platte
@jplatte
Jul 20 2016 16:48
No, my values are actual values, not wrapped types. A simple example for what I want to do is hana::filter(hana::make_tuple(0, 1, (int*)nullptr, my_type{}, hana::trait<std::is_integral>) (expected return value is a tuple of 0 and 1)
Jason Rice
@ricejasonf
Jul 20 2016 17:00
You could compose the function to turn it into a type first.
#include<boost/hana.hpp>

namespace hana = boost::hana;

struct my_type { };

constexpr auto is_type_integral = hana::compose(hana::trait<std::is_integral>, hana::typeid_);

int main()
{
  BOOST_HANA_RUNTIME_ASSERT(
    hana::equal(
      hana::filter(hana::make_tuple(0, 1, (int*)nullptr, my_type{}), is_type_integral),
      hana::make_tuple(0, 1)
    )
  );
}
hana::typeid_ was just committed recently though. hana::decltype_ works too.
Jonas Platte
@jplatte
Jul 20 2016 17:01
What do you mean by recently? Is it in the release? I'm using hana as a git submodule.
Jason Rice
@ricejasonf
Jul 20 2016 17:02
yeah just use decltype_ then unless the submodule is on the master branch
Jonas Platte
@jplatte
Jul 20 2016 17:02
It's on the release, so I'm going to use decltype_. Thanks! :)
Jason Rice
@ricejasonf
Jul 20 2016 17:03
cool np
Louis Dionne
@ldionne
Jul 20 2016 17:19
Incidentally, the default behavior for hana::trait was to turn values into hana::types if they were not already, and then to apply the trait to that type. I removed it at some point because I did not want to do this implicitly, but maybe we should consider putting it back.
Jason Rice
@ricejasonf
Jul 20 2016 17:32
Would it strip ref and cv qualifiers?
I guess if someone wanted them stripped they could still use hana::typeid_ on it first like above.
Louis Dionne
@ldionne
Jul 20 2016 17:42
I guess it should be equivalent to hana::compose(the-trait, hana::typeid_), in which case it would strip ref and cv-qualifiers.
Not sure what’s most useful there, it really depends on use case.
Jonas Platte
@jplatte
Jul 20 2016 18:17
Thanks again, to everyone involved! I just compacted down 3 function enable_if overloads into one function that is 100 times more readable! I even added a new "overload" in two lines (even shorter than adding another eval_if, because writing my own guard function worked and was incredibly easy as well. I'll try to upstream that soon) :)
Jason Rice
@ricejasonf
Jul 20 2016 18:18
:+1:
Louis Dionne
@ldionne
Jul 20 2016 18:20
Cool! If that’s anything that you can show us, please post a link or something. It’s always nice to see how Hana is being used, and it gives us data to make it even more useful.
Jonas Platte
@jplatte
Jul 20 2016 18:21
Well I can show you my current guard code right now. I can also show you the project I'm currently more or less rewriting with hana, but you'll have to wait a few more hours until I am done with the rewrite :)
Project I'm working on is https://github.com/jplatte/algebra-cxx14, which is basically a computer algebra system for the compiler :D
Louis Dionne
@ldionne
Jul 20 2016 18:24
Neat. You could also use hana::find_if to find the first lambda that satisfies your condition, and then call this.
Jonas Platte
@jplatte
Jul 20 2016 18:25
Hm?
Oh actually this doesn't work yet, although I don't understand what's happening :D
Hm, might not be the guard code that is acting weird
Hehe, it's me who is doing stupid things.
Although it also doesn't error in the way I'd like it to..
OOhh I know what's going on
I'm not throwing in constexpr context, I'm throwing in the lambda, so it's just a normal lambda that won't return but still not a compile error
(in the guard code)
Jonas Platte
@jplatte
Jul 20 2016 18:31
Updated the gist with a fix.
Louis Dionne
@ldionne
Jul 20 2016 18:39

Something like

template <typename ...Guards>
constexpr auto guard(Guards const& ...guards) {
    auto then = hana::find_if(hana::make_tuple(guards...), [](auto g) {
      return hana::first(g);
    });

    static_assert(!hana::is_nothing(then), "Non-exhaustive guards!");

    return (*then)();
}

And then you would have to call your guards with hana::pairs like (condition, lambda). The hana::find_if bit will essentially do the recursion that you otherwise have to do explicitly.

Also note that using lambdas anywhere in your code will not allow you to make it constexpr, which is an annoying limitation that will be removed in C++17.
Jonas Platte
@jplatte
Jul 20 2016 18:40
What? My compiler doesn't complain about that, I actually do that all over the place..
Also I want as little boilerplate as possible, so I don't think I like having to construct pairs of (condition, lambda)
Louis Dionne
@ldionne
Jul 20 2016 18:41
It will complain when/if you actually try to extract a constexpr value from that function. Like constexpr int result = f(…) where f’s implementation contains a lambda.
Jonas Platte
@jplatte
Jul 20 2016 18:42
Hmmm. I think that might be okay in my case, but it's still not nice.
In the end it comes down to benchmarks
Louis Dionne
@ldionne
Jul 20 2016 18:43

Also I want as little boilerplate as possible, so I don't think I like having to construct pairs of (condition, lambda)

Sure, as you wish.

Note that constexpr shouldn’t change anything w.r.t. the generated code.
Jonas Platte
@jplatte
Jul 20 2016 18:43
I think the compiler will be able to optimize the lambdas properly even without constexpr, and I definitely don't need it for the user
Okay
Louis Dionne
@ldionne
Jul 20 2016 18:44
I would be tempted to think so too. If not, it could be the subject of a bug report.
Compilers are still not great at optimizing C++14 constructs away, from what I’ve seen so far.
Jonas Platte
@jplatte
Jul 20 2016 18:46
Reminds me that a few days ago I managed to get a 1GB executable because I had debugging symbols activated, and the code where I use my algebra library has quite long terms => quite big expression templates :D
I think even with optimizations and without debugging symbols it's still a lot, so it might not be inlined aggressively enough.
Louis Dionne
@ldionne
Jul 20 2016 18:52
Try enabling LTO and stripping the executable.
Jonas Platte
@jplatte
Jul 20 2016 18:56
I did try LTO and it got me a weird error message from the linker. But it's not a big concern anyway. The important thing is that it's fast, not that it requires as little memory as possible. But does stripping the executable do anything on optimized builds? Will -O2 / -O3 still have symbols? I'm not sure I've tried debugging an optimized executable of my own yet.
Louis Dionne
@ldionne
Jul 20 2016 18:57
Optimization settings are orthogonal to symbols left in the executable, AFAIK.
If you don’t want symbols, you have to strip them away. But for strip to see that they are unused and can be removed, LTO helps a lot.
Jonas Platte
@jplatte
Jul 20 2016 18:57
Ah okay
Jonas Platte
@jplatte
Jul 20 2016 19:03
Is there a C++17 proposal for some syntactic sugar for [](auto&& x) { return x.member; } yet? :D
Louis Dionne
@ldionne
Jul 20 2016 19:04
None that I know of. Note that C++17 is finalized, and the next one is C++20.
Jonas Platte
@jplatte
Jul 20 2016 19:04
Oh, it's already finalized? Didn't know that.
Louis Dionne
@ldionne
Jul 20 2016 19:07
Hmm, I could be wrong but I think they won’t be adding any new features now.
Jason Rice
@ricejasonf
Jul 20 2016 19:54
Speaking of new features, emscripten's next-merge branch has a recent version of clang trunk that has if constexpr in it. :D
Jonas Platte
@jplatte
Jul 20 2016 19:54
Oh, emscripten is also still a thing? :D
Haven't heard from them in a while
Jason Rice
@ricejasonf
Jul 20 2016 19:55
It's pretty stable. I think most of the changes are keeping up with changes in the llvm upstream.
... and wasm
Jonas Platte
@jplatte
Jul 20 2016 19:56
It felt pretty stable already when I used it the last time, that has to be like 2 years ago.
Though getting everything set up to build something with it was quite time intensive. Do they have their own package database now?
Or some sort of online platform where you can get build scripts for popular libraries?
Jason Rice
@ricejasonf
Jul 20 2016 19:58
They have an sdk that is supposedly easy to setup, but I've only just compiled it from source which is still not too bad. (like llvm)
the libraries they support are builtin like sdl
Jonas Platte
@jplatte
Jul 20 2016 19:58
Oh no that's not what I mean
There are often special build flags you need when building / configuring libraries for emscripten
For example some libaries try to run tests as part of the build process and you have to disable that as otherwise the build tool tries to run what it believes to be test executables, but what is actually JS or LLVM IR when compiling with embuild.
Jason Rice
@ricejasonf
Jul 20 2016 20:00
using em++ will automatically create a file ~/.emscripten with all of that. You just have to fix the path names if they are different.
oh yeah libraries have to support it to some degree like any other platform
typical with cross compiling, you can't use system libraries
Jonas Platte
@jplatte
Jul 20 2016 20:02
Yeah I know that, and there are a bunch of them that actually work fine... If you know the correct configure flags. My question is if either there are binary packages with the LLVM IR / JS for popular libraries or build scripts that will automatically compile the libraries with the correct configure flags.
(and a central platform for those build scripts, so the building can be automated)
Jason Rice
@ricejasonf
Jul 20 2016 20:03
nothing that I know of
Jonas Platte
@jplatte
Jul 20 2016 20:03
I think I remember freetype2 and libogg to require some hard to find build flags to not abort the compilation with some hard to understand error message.
Hm..
Jason Rice
@ricejasonf
Jul 20 2016 20:06
Boost.Hana is just fine since it is header only :P
Jonas Platte
@jplatte
Jul 20 2016 20:06
Okay so it has moved further a tiny bit. freetype and ogg are both available builtin, so it should be a little easier for a lot of projects now
Haha I doubt anyone wants to compile such template-heavy code to JS. I think that would hurt file-sizes quite a bit ^^
Jason Rice
@ricejasonf
Jul 20 2016 20:07
not at all
Jonas Platte
@jplatte
Jul 20 2016 20:08
what?
are you sure?
Jason Rice
@ricejasonf
Jul 20 2016 20:10
None of the template stuff makes it into the js.
Jonas Platte
@jplatte
Jul 20 2016 20:13
Well the metaprogramming part doesn't, but what about tuple / set / map?
Jason Rice
@ricejasonf
Jul 20 2016 20:15
They, for the most part, store just like a struct, and the way you access them is resolved at compile time.
Louis Dionne
@ldionne
Jul 20 2016 20:16
@ricejasonf Have you compiled Hana code to JS?
Jonas Platte
@jplatte
Jul 20 2016 20:16
Yeah, but won't all the member functions be generated seperately for each template instantiation?
Jason Rice
@ricejasonf
Jul 20 2016 20:17
@jplatte yes, but it eventually gets inlined
Jonas Platte
@jplatte
Jul 20 2016 20:18
Hm, okay
Jason Rice
@ricejasonf
Jul 20 2016 20:22
@ldionne I don't think I have. I'm working on something right now, but it is kind of large. If I do a simple example with iostream that is when things get needlessly bloated.
large as in complex not bloated :P
Louis Dionne
@ldionne
Jul 20 2016 20:22
ok
Jonas Platte
@jplatte
Jul 20 2016 20:26
I'm running out of names :D
First I have normal traits, then I have _v template variables... Now I also want that trait lifted into hana, and probably also to work on values instead of basic_type's :D
well, references, not values
Jonas Platte
@jplatte
Jul 20 2016 22:04
Does someone here know why variable templates can't be used as template template parameters? That seems to be the only reason that they can't fully replace classic traits, which is kind of annoying..
Jason Rice
@ricejasonf
Jul 20 2016 22:15
Is it constexpr?
Jonas Platte
@jplatte
Jul 20 2016 22:15

I'm not talking about code that is failing on my end. I was about to try it out when I found this on cppreference:

Variable templates cannot be used as template template arguments.

Jason Rice
@ricejasonf
Jul 20 2016 22:26
oh.. I remember finding that too. I would guess that maybe it is because it is a value and not a type idk
With regard to using Boost.Hana with emscripten, I made my tests compile with it. It all uses Hana and template insanity to an extreme degree.
-rw-rw-r--  1 jason jason 135K Jul 20 15:21 individual.test.nbdl.core.context.js
-rw-rw-r--  1 jason jason  552 Jul 20 15:21 individual.test.nbdl.core.context.js.mem
-rw-rw-r--  1 jason jason  83K Jul 20 15:21 individual.test.nbdl.core.context_match.js
-rw-rw-r--  1 jason jason  552 Jul 20 15:21 individual.test.nbdl.core.context_match.js.mem
-rw-rw-r--  1 jason jason  94K Jul 20 15:21 individual.test.nbdl.core.context_state_consumer.js
-rw-rw-r--  1 jason jason  552 Jul 20 15:21 individual.test.nbdl.core.context_state_consumer.js.mem
-rw-rw-r--  1 jason jason 103K Jul 20 15:21 individual.test.nbdl.core.delta.js
-rw-rw-r--  1 jason jason 3.7K Jul 20 15:21 individual.test.nbdl.core.delta.js.mem
-rw-rw-r--  1 jason jason 100K Jul 20 15:22 individual.test.nbdl.core.entity.js
-rw-rw-r--  1 jason jason 3.7K Jul 20 15:22 individual.test.nbdl.core.entity.js.mem
-rw-rw-r--  1 jason jason  90K Jul 20 15:21 individual.test.nbdl.core.map_store.js
-rw-rw-r--  1 jason jason  936 Jul 20 15:21 individual.test.nbdl.core.map_store.js.mem
-rw-rw-r--  1 jason jason  69K Jul 20 15:22 individual.test.nbdl.core.message_api.js
-rw-rw-r--  1 jason jason  552 Jul 20 15:22 individual.test.nbdl.core.message_api.js.mem
-rw-rw-r--  1 jason jason  68K Jul 20 15:22 individual.test.nbdl.core.path.js
-rw-rw-r--  1 jason jason  552 Jul 20 15:22 individual.test.nbdl.core.path.js.mem
-rw-rw-r--  1 jason jason  68K Jul 20 15:22 individual.test.nbdl.core.provider_map.js
-rw-rw-r--  1 jason jason  552 Jul 20 15:22 individual.test.nbdl.core.provider_map.js.mem
-rw-rw-r--  1 jason jason  78K Jul 20 15:22 individual.test.nbdl.core.store.js
-rw-rw-r--  1 jason jason  936 Jul 20 15:22 individual.test.nbdl.core.store.js.mem
-rw-rw-r--  1 jason jason 100K Jul 20 15:16 individual.test.nbdl.core.variant.js
-rw-rw-r--  1 jason jason 3.7K Jul 20 15:16 individual.test.nbdl.core.variant.js.mem
-rw-rw-r--  1 jason jason  54K Jul 20 15:16 Makefile
-rw-rw-r--  1 jason jason  57K Jul 20 15:20 test.nbdl.core.detail.concept_pred.js
-rw-rw-r--  1 jason jason  113 Jul 20 15:20 test.nbdl.core.detail.concept_pred.js.mem
-rw-rw-r--  1 jason jason 223K Jul 20 15:21 test.nbdl.core.js
-rw-rw-r--  1 jason jason 4.1K Jul 20 15:21 test.nbdl.core.js.mem
Those are the file sizes with "Release" which I think defaults to -O2. I also think emscripten "strips" symbols for you.
Jason Rice
@ricejasonf
Jul 20 2016 22:31
Note that each of those js files has the overhead of a js virtual machine.
Louis Dionne
@ldionne
Jul 20 2016 22:36
Does that look reasonable for a JS file?
Jonas Platte
@jplatte
Jul 20 2016 22:37
Emscripten output is not human-readable, if that's what you mean
Louis Dionne
@ldionne
Jul 20 2016 22:37
Ok. But I was talking about the size, is ~100K reasonable or is it expected to be much smaller?
How large are typical files generated with emscripten?
Jonas Platte
@jplatte
Jul 20 2016 22:41
Really depends on what you do. I think if it's just logic the file sizes will never be bigger than a few 100kb. It's definitely more than handwritten JS, but it can be faster, because it's a low-level subset of JS. But I think JS VMs have gotten pretty good at optimizing high-level code as well. My personal opinion is that emscripten is only worth it when you want to port existing code or share logic in frontend and backend, because the performance can be optimized in different ways and you will always have a size overhead over more highlevel JS.
If you port a full game to the web with emscripten, the code is going to be multiple MBs worth of download, but there it hardly matters because the assets are always bigger anyway.
Jason Rice
@ricejasonf
Jul 20 2016 22:43
I'm guessing that the jsvm itself is probably ~60k. I've worked on large js apps that were >6Mb. Javascript would generally be smaller, but npm and such come with their own bloat and they can't eliminate dead code very well.
Jonas Platte
@jplatte
Jul 20 2016 22:43
@ricejasonf What VM are you talking about, actually?
C++ doesn't have a runtime..
Jason Rice
@ricejasonf
Jul 20 2016 22:44
emscripten is the runtime. It has heap management and all of that
Jonas Platte
@jplatte
Jul 20 2016 22:44
Oh right, the lowlevel stuff. Is that really called "VM" though?
Jason Rice
@ricejasonf
Jul 20 2016 22:45
eh idk
:P
Jonas Platte
@jplatte
Jul 20 2016 23:54
Now I am experiencing a really weird problem...
Apparently with decltype(a) == false_c and decltype(b) == false_c, decltype(a && b) == bool?!
That can't be...
Jason Rice
@ricejasonf
Jul 20 2016 23:57
false_c is a constexpr value
of type false_
Jonas Platte
@jplatte
Jul 20 2016 23:58
... and it is not the case. So where is that bool coming from..
Jason Rice
@ricejasonf
Jul 20 2016 23:58
Do you mean hana::decltype_?
Jonas Platte
@jplatte
Jul 20 2016 23:58
I just mean the types
That I see in the compiler error message
I have a function with this body:
return guard(
            is_term(lhs) && is_term(rhs), [&](auto _) { return sub(_(lhs), rhs); },
            is_term(lhs),                 [&](auto _) { return sub(_(lhs), constant(rhs)); },
            is_term(rhs),                 [&](auto _) { return sub(_(constant(lhs)), rhs); });
(I added the _ because of errors that are probably related, I shouldn't need that..)