Compile-time fold results in error when called with a lambda - d

I'm trying to fold an array at compile time, and store the result in an enum. It works just fine when the enum (and call to fold) is at module-level, but compilation fails when its both contained within a struct and called using a lambda.
Here's a simple example of some failing code:
import std.algorithm.iteration;
import std.stdio;
struct Foo
{
// Version 1 (works)
//enum x = [ 1, 2, 3 ].fold!"a * b";
// Version 2 (works)
//enum x = [ 1, 2, 3 ].fold!mult;
// Version 3 (broken)
enum x = [ 1, 2, 3 ].fold!((a, b) => a * b);
pragma(msg, "x = ", x);
}
// Outside of the struct, it works
enum y = [ 1, 2, 3 ].fold!((a, b) => a * b);
pragma(msg, "y = ", y);
int mult(int a, int b)
{
return a * b;
}
void main(){}
(Versions 1 and 2, which are commented out, compile just fine. It's just Version 3 that has problems.)
Upon compiling, the following error is thrown:
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3690): Error: `this.__lambda2` has no value
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3690): while evaluating: `static assert(((int)).length == fun.length)`
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3697): Error: `this.__lambda2` has no value
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3718): Error: `this.__lambda2` has no value
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(3636): Error: template instance `broken.Foo.reduce!((a, b) => a * b).reduceImpl!(false, int[], int)` error instantiating
C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm\iteration.d(4086): instantiated from here: `reduce!(int[])`
.\broken.d(13): instantiated from here: `fold!(int[])`
x = .\broken.d(13): Error: CTFE failed because of previous errors in `fold`
.\broken.d(16): while evaluating `pragma(msg, x)`
y = 6
Failed: ["C:\\D\\dmd2\\windows\\bin\\dmd.exe", "-v", "-o-", ".\\broken.d", "-I."]
I've tried looking at the source code mentioned in the error, but the concepts it uses are beyond my current level of knowledge of D.
I initially assumed that lambdas might not work properly at compile-time, but enum y evaluates correctly, so I'm guessing it's not that...
I'm using DMD v2.086.1, but had the same problem using LDC 1.16.0 and 1.14.0.

This is the compiler not being very good at figuring out if a lambda needs access to its context. If you'd written something like this:
struct S {
int n;
int fun() {
import std.algorithm.iteration : fold;
return [1,2,3].fold!((a,b) => a*b*n);
}
}
It should be clear that the lambda above needs access to n in the struct. In the same way, the compiler errs on the side of caution for enum x = [ 1, 2, 3 ].fold!((a, b) => a * b);, and assumes there's some state inside Foo that will affect the result of the calculation. Filed this as issue 20077.
You have already found some workarounds, and there's another worth mentioning - adding argument types to the lambda:
enum x = [ 1, 2, 3 ].fold!((int a, int b) => a * b);
This way, the compiler figures out what info the lambda needs at an earlier point, and is able to figure out that it doesn't need access to the surrounding scope.

Related

Pybind11: How to assign default value for a struct member variable?

I am trying to create python bindings for the below
struct example {
int a = 1;
int b = 2;
};
This is what I have so far
PYBIND11_MODULE(example_python, m) {
py::class_<example>(m, "example")
.def_readwrite("a", &example::a)
.def_readwrite("b", &example::b);
}
when I checked in python, both a and b are empty, so I tried something like
PYBIND11_MODULE(example_python, m) {
py::class_<example>(m, "example")
.def_readwrite("a", &example::a, py::arg("a") = 1)
.def_readwrite("b", &example::b, py::arg("b") = 2);
}
but this results in a compilation error. I went through the documentation multiple times but couldn't a way to do it. Can someone let me know how to assign the default values in pybind11?
Your code doesn't compile, at least on my machine, because you didn't bind any constructor. However, if you do so then the default values become populated (because that's part of what a constructor does!). In other words, just use this:
PYBIND11_MODULE(example_python, m) {
py::class_<example>(m, "example")
.def(py::init<>()) // <-- bind the default constructor
.def_readwrite("a", &example::a)
.def_readwrite("b", &example::b);
}

std::make_shared not working, but creating the pointer using "new" works fine

I am currently making a GUI system for my game engine. I tried to create a shared pointer for one of the components "GUImovingbar" using std::make_shared() but got the following error when compiling
'std::shared_ptr<_Other> std::make_shared(_Types &&...)': could not deduce template argument for '_Types &&...' from 'initializer list'
However, when I used the exact same inputs to create a new pointer, it compiled fine with no errors. This struck me as a bit odd. What am I missing here?
Code using std::make_shared():
this->playerhullbar = std::make_shared<GUImovingbar>(
"right",
{ 50,hully }, //scoords
globalguitextures[findStringSrdPointerPairVectElement(globalguitextures, "barbackground")].second,
{ 0,static_cast<double>(maxplayerhullint),static_cast<double>(maxplayerhullint) },
{ 50,hully,250, hully,2,100 },//for int vector input ("bsbebdbc"): 1 barxstart, 2 y , 3 barendx, 4 y, 5 distance between bars in px, 6 bar count
{ 0,255,0 },
bartextvect
);
Above causes error:
'std::shared_ptr<_Other> std::make_shared(_Types &&...)': could not deduce template argument for '_Types &&...' from 'initializer list'
The following causes no errors at all:
std::shared_ptr<GUImovingbar> newptr(new GUImovingbar(
"right",
{ 50,hully}, //scoords
globalguitextures[findStringSrdPointerPairVectElement(globalguitextures, "barbackground")].second,
{ 0,static_cast<double>(maxplayerhullint),static_cast<double>(maxplayerhullint) },
{ 50,hully,250, hully,2,100 },//for int vector input ("bsbebdbc"): 1 barxstart, 2 y , 3 barendx, 4 y, 5 distance between bars in px, 6 bar count
{ 0,255,0 },
bartextvect)
);
this->playerhullbar = newptr;
As a template function, std::make_shared tries to find the appropriate constructor for your class given the parameters it has. Since you've given it initializer lists (the stuff in brackets), it is confused about what type those lists are supposed to initialize, and it thus can't find the appropriate constructor. However, when you use the constructor proper, ambiguity is removed, since thanks to the parameters' position the compiler knows what type the lists are supposed to initialize, and it converts them accordingly.
If you still want to use std::make_shared, you'll have to disambiguate the types of the initializer lists by putting them before the list :
this->playerhullbar = std::make_shared<GUImovingbar>(
"right",
Scoords { 50,hully },
globalguitextures[findStringSrdPointerPairVectElement(globalguitextures, "barbackground")].second,
Rect { 0,static_cast<double>(maxplayerhullint),static_cast<double>(maxplayerhullint) },
std:vector<int> { 50,hully,250, hully,2,100 },
Color { 0,255,0 },
bartextvect
);
(or, if you have an old compiler, use the former syntax with parentheses as well : std:vector<int>({ 50,hully,250, hully,2,100 }))
The problems are the aggregate initializations that you're doing in the make_shared call. If you create an object with new GUImovingbar(...) you are directly calling the constructor and thus, the compiler knows exactly which argument is of which type. This enables you to aggregate initialize said arguments.
However, if you call make_shared all arguments must be deduced from the value that you pass to the function (because it's a template). This would basically be like this:
auto x = {10, "hello", 4};
How should the compiler know what type this actually is?
If you still want to use make_shared you have to explicitly initialize the types with their names.

Is there a way to specify an enum-class value without having to type out its scope every time?

I have some functions that can return either success or one of a fixed set of error codes. To identify the error codes, I had (something like) this old-school C-style enum declared:
enum {
RESULT_ERROR_BAD_PARAMETER = -3,
RESULT_ERROR_FILE_NOT_FOUND = -2,
RESULT_ERROR_GENERAL = -1,
RESULT_SUCCESS = 0
};
typedef int my_status_t;
my_status_t MyFunc(); // returns a RESULT_* value
This worked pretty well; the calling pattern would be something like:
if (MyFunc() != RESULT_SUCCESS) printf("Error!\n");
... however it was uncomfortably permissive about allowing implicit conversions of my_status_t values to int/bool/etc, allowing careless mistakes like this:
// Compiles but does the wrong thing at run-time -- bad!
if (MyFunc() == false) printf("Error!\n");
... so in my new code revision, I converted it to be an enum class instead:
enum class my_status_t {
RESULT_ERROR_BAD_PARAMETER = -3,
RESULT_ERROR_FILE_NOT_FOUND = -2,
RESULT_ERROR_GENERAL = -1,
RESULT_SUCCESS = 0
};
... this works great from a compile-time checking perspective; now most unintentional type-promotions are caught by the compiler, forcing the programmer to go back and do it the right way.
The only thing that bothers me is that the new syntax is tedious: now I have to write something like:
if (MyFunc() != my_status_t::RESULT_SUCCESS) printf("Error!\n");
... at every call site -- having to type out my_status_t:: each time is tedious and makes the code harder to read, without really adding much value (since RESULT_SUCCESS is sufficiently unique for my purposes on its own, anyway)
My question is, is there some kind of using namespace my_status_t; style directive I could use to tell the compiler to export the enum-values out of their my_status_t namespace, so that I could reference them without having to type the my_status_t:: prefix all the time?
If you going to be typing a lot more of the nuisance scope-prefixes than there
are constants in the enum class, then it may be worth your while to go with this
way:
enum class result {
ERROR_BAD_PARAMETER = -3,
ERROR_FILE_NOT_FOUND = -2,
ERROR_GENERAL = -1,
SUCCESS = 0
};
constexpr result RESULT_ERROR_BAD_PARAMETER = result::ERROR_BAD_PARAMETER;
constexpr result RESULT_FILE_NOT_FOUND = result::ERROR_FILE_NOT_FOUND;
constexpr result RESULT_ERROR_GENERAL = result::ERROR_GENERAL;
constexpr result RESULT_SUCCESS = result::SUCCESS;
result foo() {
return RESULT_SUCCESS;
}
int main()
{
switch (foo())
{
case RESULT_SUCCESS:
;
}
// ^ warning: enumeration value ‘...’ not handled in ...
if (foo() == RESULT_SUCCESS) {
return 0;
}
/* error: no match for ‘operator==’
if (foo() == false) {
return -1;
}
*/
}
(g++ -Wall -Wextra -pedantic -std=c++11)
Do this change:
enum class result {
ERROR_BAD_PARAMETER = -3,
ERROR_FILE_NOT_FOUND = -2,
ERROR_GENERAL = -1,
SUCCESS = 0
};
because your enumerated values are in a scope, you no longer have to give them as long a name.
Now your code becomes:
if (MyFunc() != result::SUCCESS) printf("Error!\n");
which is a whole 1 character longer than before.
You could also
using my_status_t = result;
if you are tied to my_status_t as a type name.
As of C++17 there is no way to cleanly avoid the result:: prefix. There is talk about using ERROR_BAD_PARAMETER = result::ERROR_BAD_PARAMETER; or the like in later versions of C++, but I'm unaware if they are going to get into c++20.
Here's a way:
enum class my_status_t { };
inline constexpr my_status_t RESULT_ERROR_BAD_PARAMETER = my_status_t(-3);
// add other enum values here
Unfortunately, this way you lose some good properties of enum. Like compiler can warn you if you don't handle a value in a switch (and don't forget to set the underlying type of enum class, if you have big values).
So I actually don't recommend this way (I better like Yakk's solution), but maybe this answer can help you anyway...

Why I get no identifier for declarator ....?

Why I get no identifier for declarator .... ?
mixin are useless in this case but that is a minimal example of my problem.
tlvar is type of TL so i do not see where is the problem.
Code also on dpaste, same error with dmd or ldc.
Thanks for your help
import std.stdio;
import std.typecons;
struct Data{
int x;
int y;
}
template getcode(T)
{
mixin(`
alias TL = Tuple!(
int,"x",
int,"y"
);
`);
TL tl;
mixin(`
tl.x = 10;
tl.y = 5;
`);
}
void main()
{
getcode!Data;
writeln( tl.x );
}
Your problem is that templates can only contain declarations, not statements or expressions. This is the offending code:
mixin(`
tl.x = 10;
tl.y = 5;
`);
These are assignments, not declarations. This is why you get the weird error message "Error: no identifier for declarator tl.x". The compiler thinks you are trying to make a declaration of a variable, and it can't find the type "tl.x"... or something like that. The solution is to set the value of the tuple inline, like so:
template getcode(T)
{
mixin(`alias TL = Tuple!(int, "x", int, "y");`);
TL tl = TL(10, 5);
}
Or, to better match your original code:
template getcode(T)
{
mixin(`alias TL = Tuple!(int, "x", int, "y");`);
TL tl = mixin(`TL(10, 5)`);
}
There is now another problem. In main, where you instantiate the template, you will get the error "Error: getcode!(Data) has no effect". This is because a template instantiation on its own is not a declaration. You have to either alias it to a symbol, or mix it in using a mixin statement.
Aliasing it to a symbol will allow you to access the declarations inside the template through that symbol, and mixing it in puts the template's declarations into the scope it's instantiated in. I would recommend the first option, as it's more hygenic. You shouldn't use mixin unless you absolutely have to.
void main()
{
//Error: getcode!(Data) has no effect
//getcode!Data;
//Ok
//mixin getcode!Data;
//writeln( tl.x );
//Ok
alias Code = getcode!Data;
writeln( Code.tl.x );
}
You can see my corrected version of your code here:
http://dpaste.dzfl.pl/f6152a35bfc8

Cartesian product of immutable ranges

Why can't we compute the cartesian product of two immutable ranges ?
The following code :
import std.stdio;
import std.algorithm;
void main() {
immutable int[] B = [ 1, 2, 3 ];
immutable int[] C = [ 4, 5, 6 ];
auto BC = cartesianProduct(B, C);
writeln(BC);
}
Throws :
/usr/include/dmd/phobos/std/range.d(4199): Error: cannot modify struct result._ranges_field_1 Repeat!(immutable(int)) with immutable members
/usr/include/dmd/phobos/std/range.d(4503): Error: template instance std.range.Zip!(immutable(int)[], Repeat!(immutable(int))) error instantiating
/usr/include/dmd/phobos/std/algorithm.d(11674): instantiated from here: zip!(immutable(int)[], Repeat!(immutable(int)))
laurent_test.d(8): instantiated from here: cartesianProduct!(immutable(int)[], immutable(int)[])
/usr/include/dmd/phobos/std/algorithm.d(11674): Error: template instance std.range.zip!(immutable(int)[], Repeat!(immutable(int))) error instantiating
laurent_test.d(8): instantiated from here: cartesianProduct!(immutable(int)[], immutable(int)[])
laurent_test.d(8): Error: template instance std.algorithm.cartesianProduct!(immutable(int)[], immutable(int)[]) error instantiating
Futhermore, if the second but the first immutable is removed it works.
According to the phobos implementation, one of the range as to be an inputRange and the other a forwardRange. Why such template constraints ?
I'm definitely not an expert in D, but I asked a similar question last year and this answer from Jonathan M Davis was excellent.
TL;DR: A range can't be immutable because it would't respect the 4 rules:
R r = void; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
Can you guess the culprint? popFront