Re: Linking a C program with D library
On Wednesday, 15 August 2018 at 01:56:34 UTC, Mike Parker wrote: The correct thing to do is to keep the original C function signatures in the converted code, i.e. don't change char* to string[]. And don't use anything from Phobos internally that requires linking. In other words, treat your converted code as C code in a D module as much as possible. Only when the conversion is complete and everything is in D do you start pulling in the D features. I understand that, Mike. However if I'm not mistaken given something in C like char* strs[] = { "This", "is a", "test"}; AFAIK, even with -betterC and an extern (C), the literals will still be understood by D as type "string", and there is no other way around it, right? I could put the array and the function in its own C file for the time being, but instead chose to replace the toStringz by a small hack: use memcpy to copy the string to a stack fixed, big enough array and a NUL terminator.
Re: Linking a C program with D library
On Tuesday, 14 August 2018 at 23:05:26 UTC, Joe wrote: I'm attempting a piecemeal conversion of some C programs. I've converted a few that depend on C modules that are in a library and now I'm sort of in the middle of converting those C modules. One of them has an array of strings, i.e., array of char*, which most easily translated to D's string[]. However, the array is used by a function that expects a const char*, so I had to use toStringz to pass those values. Now there are some C programs that haven't been converted yet, but they depend on the function above. When linking those programs, the linker complains about an undefined reference to the mangled name of std.string.toStringz. What is the most appropriate way around this? Is there a way to declare an array of const char* and initialize it to literal strings? Or can the mangled name (and Phobos library) somehow be made visible to the linker? The correct thing to do is to keep the original C function signatures in the converted code, i.e. don't change char* to string[]. And don't use anything from Phobos internally that requires linking. In other words, treat your converted code as C code in a D module as much as possible. Only when the conversion is complete and everything is in D do you start pulling in the D features.
Linking a C program with D library
I'm attempting a piecemeal conversion of some C programs. I've converted a few that depend on C modules that are in a library and now I'm sort of in the middle of converting those C modules. One of them has an array of strings, i.e., array of char*, which most easily translated to D's string[]. However, the array is used by a function that expects a const char*, so I had to use toStringz to pass those values. Now there are some C programs that haven't been converted yet, but they depend on the function above. When linking those programs, the linker complains about an undefined reference to the mangled name of std.string.toStringz. What is the most appropriate way around this? Is there a way to declare an array of const char* and initialize it to literal strings? Or can the mangled name (and Phobos library) somehow be made visible to the linker?
Re: write a function template specialisation that tests if an argument is known at compile time
On Tuesday, 14 August 2018 at 03:01:11 UTC, Cecil Ward wrote: On Tuesday, 14 August 2018 at 02:53:01 UTC, Cecil Ward wrote: On Sunday, 12 August 2018 at 12:27:59 UTC, Alex wrote: On Saturday, 11 August 2018 at 05:17:51 UTC, Cecil Ward wrote: T myfunc(T)( T x, uint mask ) if ( mask == 3 ) { return fast_func( x, mask ); } [...] Is it the volcano pattern you are looking for? https://p0nce.github.io/d-idioms/#Is-this-available-at-compile-time-or-runtime? Wow, now that _is_ clever. I think that is definitely a big part of it. Now somehow after having used a static if to select the known-at-compile-time case I then have to test the argument for particular values. So how to get the next step along the way? Would it be ok to ask Walter maybe ? I am so far out of my depth here tho. If you are that far, then it seems simple. You always call it as a template: T myfunc(uint mask, T)(T x) {} In myfunc you decide if umask is compile time or not. If not, then call a templated function with static if's for specific values, otherwise call the regular function.
Re: Concat enum of strings into one string
On Tuesday, August 14, 2018 8:37:33 AM MDT Andrey via Digitalmars-d-learn wrote: > On Tuesday, 14 August 2018 at 14:07:23 UTC, Timoses wrote: > > Here's one version: > > > > template StringEnumValues(alias Enum) > > { > > > > import std.traits : EnumMembers; > > string[] StringEnumValues() > > { > > > > string[] enumValues; > > > > static foreach (member; EnumMembers!Enum) > > > > enumValues ~= member; > > > > return enumValues; > > > > } > > > > } > > > > import std.string : join; > > pragma(msg, StringEnumValues!Type.join(" ")); > > Thank you. Hmm, I thought that standard library already has this > stuff. Phobos isn't generally going to have super-specific stuff like a function for taking an enum type and giving you a string containing the names of all of its members separated by a single space. Rather, it has building blocks for doing stuff like that. EnumMembers is one of those building blocks, and as vit showed in his post, its possible to use map instead of a loop like is done here. So, getting compact code is often a question of figuring out which building blocks get you what you want. But it's frequently the case that you need several traits, functions, and/or templates to get where you want to go. For metaprogramming, std.traits and std.meta are the main places to look, whereas for operating on runtime values (or using CTFE instead of template metaprogramming), std.range and std.algorithm are the main places to look, though depending on what you're doing, pretty much anywhere in Phobos could be useful. It's just that std.range and std.algorithm are where the most generic stuff is (as opposed to something like std.string which is specific to strings or std.file which has file-specific operations). At first, you're likely to end up with code that looks more like what Timoses suggested, and over time, it will become easier to come up with solutions closer to what vit suggested, and it probably won't be uncommon to start off with a more verbose solution and then end up with a more compact one later when you figure out how a particular piece of Phobos can be used to solve the problem in less space. But there's enough in Phobos (even std.algorithm alone) that it's not all that hard to not realize that something that's perfect for your problem is in there. It is usually a building block towards the solution though rather than a function that does exactly what you want at the high level. - Jonathan M Davis
Re: is this a betterC bug ?
On Tuesday, 14 August 2018 at 17:22:42 UTC, Seb wrote: FYI: staticArray will be part of 2.082, it already works with dmd-nightly: That just seems wrong. Isn't the fact that `staticArray` is needed a bug in the compiler? I think the compiler could have lowered to something like that automatically to avoid the library workaround. Mike
Re: is this a betterC bug ?
On Tuesday, 14 August 2018 at 16:31:38 UTC, Paul Backus wrote: On Tuesday, 14 August 2018 at 13:01:57 UTC, learnfirst1 wrote: enum string[] a = ["a"]; extern(C) void main() { int i = 0; auto s = a[i]; } --- Error: TypeInfo cannot be used with -betterC Workaround: https://run.dlang.io/is/NZykl0 Source: https://p0nce.github.io/d-idioms/ FYI: staticArray will be part of 2.082, it already works with dmd-nightly: https://run.dlang.io/is/tC7tix
Re: Enum and CTFE function call
On Tuesday, 14 August 2018 at 16:54:09 UTC, ixid wrote: On Tuesday, 14 August 2018 at 13:38:16 UTC, Everlast wrote: etc Thanks all for the comprehensive responses. I was not clearly separating CTFE and the compilation of the function in thinking about it. Much clearer now. Yeah, if you don't think's can get pretty confusing because the language really does not cleanly separate it... which is intention because they are virtually identical things but used slightly differently(technically RT and CT are not separate things, we could assume the OS is a compiler of some sorts). I will say that once you do some meta programming in D(say 10k lines of code, even if basically junk but in some higher context) it will just sorta of magically start to separate pretty quickly. Since they are so similar you really are not learning anything new if you already know how to program well(have a good conceptual basis of what programming is and how it works, say about ~5 years of decent programming experience). Just remember that it won't all suddenly be crystal clear, the more you program this stuff the more clear the divisions become(And everything D in general). Initially when I started messing with D the concepts were not obvious but once I recognized the power unadulterated power that they posses(which was quick since I love meta programming in general) and the ease of use(I just had to think in basically those 3 categories without changing much actually programming "logic") I was hooked. Of course, it's not perfect, but nothing out there like it that is like C++(which was my background). I'm not much in to Haskell, which is effectively even a more powerful logic device, but just unlike the rigor that is required to use it. (When I want to be risky I want to be risque!). D provides that balance, as a language, for me... all though it isn't a perfect marriage by any means(are any?).
Re: Enum and CTFE function call
On Tuesday, 14 August 2018 at 13:38:16 UTC, Everlast wrote: etc Thanks all for the comprehensive responses. I was not clearly separating CTFE and the compilation of the function in thinking about it. Much clearer now.
Re: is this a betterC bug ?
On Tuesday, 14 August 2018 at 13:01:57 UTC, learnfirst1 wrote: enum string[] a = ["a"]; extern(C) void main() { int i = 0; auto s = a[i]; } --- Error: TypeInfo cannot be used with -betterC Workaround: https://run.dlang.io/is/NZykl0 Source: https://p0nce.github.io/d-idioms/
Re: Concat enum of strings into one string
On Tuesday, 14 August 2018 at 14:37:33 UTC, Andrey wrote: On Tuesday, 14 August 2018 at 14:07:23 UTC, Timoses wrote: Here's one version: template StringEnumValues(alias Enum) { import std.traits : EnumMembers; string[] StringEnumValues() { string[] enumValues; static foreach (member; EnumMembers!Enum) enumValues ~= member; return enumValues; } } import std.string : join; pragma(msg, StringEnumValues!Type.join(" ")); Thank you. Hmm, I thought that standard library already has this stuff. import std.traits : EnumMembers; import std.string : join; import std.algorithm : map; pragma(msg, [EnumMembers!Type].map!(x => cast(string)x).join(" "));
Re: is this a betterC bug ?
On Tuesday, 14 August 2018 at 13:01:57 UTC, learnfirst1 wrote: enum string[] a = ["a"]; extern(C) void main() { int i = 0; auto s = a[i]; } --- Error: TypeInfo cannot be used with -betterC You can use `static immutable` as a workaround for now: https://run.dlang.io/is/7HEPst
Re: Concat enum of strings into one string
On Tuesday, 14 August 2018 at 14:37:33 UTC, Andrey wrote: Thank you. Hmm, I thought that standard library already has this stuff. There might be more elegant solutions and I'd be happy to see some more. I'm always just digging into std.traits [1] and Traits spec part [2] and try to fumble things together somehow until I get what I want. It's good practice (as in training/accustomization, not as in method...), but perhaps also a sign that there's an area for improvement. [1] https://dlang.org/phobos/std_traits.html [2] https://dlang.org/spec/traits.html
Re: Concat enum of strings into one string
On Tuesday, 14 August 2018 at 14:07:23 UTC, Timoses wrote: Here's one version: template StringEnumValues(alias Enum) { import std.traits : EnumMembers; string[] StringEnumValues() { string[] enumValues; static foreach (member; EnumMembers!Enum) enumValues ~= member; return enumValues; } } import std.string : join; pragma(msg, StringEnumValues!Type.join(" ")); Thank you. Hmm, I thought that standard library already has this stuff.
Re: Concat enum of strings into one string
On Tuesday, 14 August 2018 at 13:42:04 UTC, Andrey wrote: Hello, I have a enum: enum Type : string { One = "Q1", Two = "W2", Three = "R3" } I want to concat it in compile-time: enum result = doConcat!Type(); And get this result: writeln(result); // output: "Q1 W2 R3" Delimiter here is space symbol. How do do it? Here's one version: template StringEnumValues(alias Enum) { import std.traits : EnumMembers; string[] StringEnumValues() { string[] enumValues; static foreach (member; EnumMembers!Enum) enumValues ~= member; return enumValues; } } import std.string : join; pragma(msg, StringEnumValues!Type.join(" "));
Re: Concat enum of strings into one string
On Tuesday, 14 August 2018 at 13:45:48 UTC, Mike Franklin wrote: I think you just need to use the concatenation operator `~`. enum Type : string { One = "Q1", Two = "W2", Three = "R3" } enum concatenation = Type.One ~ " " ~ Type.Two ~ " " ~ Type.Three; void main() { import std.stdio: writeln; writeln(concatenation); } Mike Hmm, and to do it automatically, not manually?
Re: Concat enum of strings into one string
On Tuesday, 14 August 2018 at 13:42:04 UTC, Andrey wrote: Hello, I have a enum: enum Type : string { One = "Q1", Two = "W2", Three = "R3" } I want to concat it in compile-time: enum result = doConcat!Type(); And get this result: writeln(result); // output: "Q1 W2 R3" Delimiter here is space symbol. How do do it? I think you just need to use the concatenation operator `~`. enum Type : string { One = "Q1", Two = "W2", Three = "R3" } enum concatenation = Type.One ~ " " ~ Type.Two ~ " " ~ Type.Three; void main() { import std.stdio: writeln; writeln(concatenation); } Mike
Concat enum of strings into one string
Hello, I have a enum: enum Type : string { One = "Q1", Two = "W2", Three = "R3" } I want to concat it in compile-time: enum result = doConcat!Type(); And get this result: writeln(result); // output: "Q1 W2 R3" Delimiter here is space symbol. How do do it?
Re: Enum and CTFE function call
On Tuesday, 14 August 2018 at 09:12:30 UTC, ixid wrote: This will not compile as it says n is not known at compile time: auto fun(int n) { static foreach(i;0..n) mixin(i.to!string ~ ".writeln;"); return; } enum value = 2; void main() { fun(value); } But making it a template parameter fun(int n)() and fun!value will obviously work as will replacing n in the foreach statement with the enum 'value'. It seems like a missed opportunity that the enum nature of 'value' does not propagate through the function call letting the compiler know that 'value'and therefore n are known at compile time. You are not understand what is going on: Your fun is a runtime function in n. That is, it cannot, under any circumstances, treat n as a compile time variable! n IS NOT a compile time variable... it doesn't matter how you use fun, it is irrelevant. static foreach is a compile time loop(that is computed at compile time and the compiler can compute things about it(such as unrolling it). CTFE means compile time FUNCTION EXECUTION! Essentially it takes the runtime function and uses compiles it to a mini program that just contains that function, then the compiler calls the function with the *known* values. Since the function is known(defined) at compile time(obvious, since virtual all functions are in programming except self modifying functions, which are almost never used), the compiler can then evaluate the result at compile time and use that instead. So, CTFE is no different than thinking about functions in a language without CTFE except you can treat them as also being sort of compile time functions when your inputs are known at compile time. CTFE functions will do what they behave just as if they did them at run time(although you can create different versions for compile time or run time execution if you need to have different behavior(doesn't change the conceptualization though)). So, when I look at fun, I see n is a run-time parameter. I then see a static foreach, which can only work over compile time(info known at compile time) using n... which states something is invalid. The proper way: auto fun(int n) { [static] foreach(i;0..n) [mixin(i.to!string ~ ".writeln;");] i.to!string.writeln; return; } and you might say! "Well, that is how I would do it at runtime!"(old school, so to speak) YES! CTFE is runtime! it is not compile time! When you call fun(3); The compiler realizes the input, n, is actually known at compile time so it tries to do this "optimization"(which, basically, is all CTFE is)... and it will effectively compile fun and use it internally to figure out what fun(3) is. If you want, you can think of the compiler magically rewriting fun as auto funCTFE(int n)() { static foreach(i;0..n) mixin(i.to!string ~ ".writeln;"); return; } and then it calls not fun(3) but funCTFE(3). or, we could see that the compiler "wraps" all functions as auto funRT(int n) { foreach(i;0..n) i.to!string.writeln; return; } auto funCT(int n)() { static foreach(i;0..n) mixin(i.to!string ~ ".writeln;"); return; } auto fun(int n1)(int n2) { if (__ctfe) return funCT!n1; else return funRT(n2); } and then it replaces the "fun(3)" with fun!3(3). I'm not saying this is what it does internally(it could, more or less) but this is what you think about it to understand it. When I see a function, it doesn't phase me one bit if it is CTFE or not. CTFE really has nothing to do with meta programming and it is just an optimization(pre-computes the value of something at compile time if it can so it doesn't have to be done at runtime every time it is used). It just happens that CTFE and meta programming work well together and hence they are used together often. What you are failing at is probably making that realization(CTFE is not meta programming!! One can just use them to do really effective meta programming because it allows one to think of meta functions as normal runtime functions). Meta programming, OTH, is realizing that if a value is defined or will be defined at compile time then you can programming against(or rather with) that to create polymorphic(different) compile time behaviors. Templates are simply "compile time" functions(which is not the same as compile time function execution!). Runtime function - a function that has at least one input that can only be determined when the application is ran(and not at compile time). These functions cannot be used by the compiler since the input is not known. Of course, CTFE can use them because even though the inputs are not known, from the functions perspective, they are actually known to the program and so CTFE is used to evaluate them. Compile time function s - a
Re: is this a betterC bug ?
On Tuesday, 14 August 2018 at 13:16:50 UTC, Nicholas Wilson wrote: On Tuesday, 14 August 2018 at 13:01:57 UTC, learnfirst1 wrote: enum string[] a = ["a"]; extern(C) void main() { int i = 0; auto s = a[i]; } --- Error: TypeInfo cannot be used with -betterC Yes. https://issues.dlang.org/show_bug.cgi?id=19169 This seems to be because dynamic array literals are allocated by default. So that is possibly not a bug, per se but the error message is definitely not helpful.
Re: is this a betterC bug ?
On Tuesday, 14 August 2018 at 13:01:57 UTC, learnfirst1 wrote: enum string[] a = ["a"]; extern(C) void main() { int i = 0; auto s = a[i]; } --- Error: TypeInfo cannot be used with -betterC Yes. https://issues.dlang.org/show_bug.cgi?id=19169
Re: Enum and CTFE function call
On Tuesday, 14 August 2018 at 11:25:06 UTC, Jonathan M Davis wrote: On Tuesday, August 14, 2018 4:03:11 AM MDT Michael via Digitalmars-d-learn wrote: [...] CTFE is triggered when a value must be known at compile-time. So, if you have something like [...] That is much clearer now, thanks for clarifying.
is this a betterC bug ?
enum string[] a = ["a"]; extern(C) void main() { int i = 0; auto s = a[i]; } --- Error: TypeInfo cannot be used with -betterC
Re: Enum and CTFE function call
On Tuesday, August 14, 2018 4:03:11 AM MDT Michael via Digitalmars-d-learn wrote: > The page does state that enums should trigger CTFE though. CTFE is triggered when a value must be known at compile-time. So, if you have something like enum a = foo(); foo gets called at compile-time, because an enum's value must be known at compile-time. So, in that sense, enums do trigger CTFE. However, using an enum does not necessarily require CTFE. e.g. void main() { enum a = 42; auto result = foo(a); } uses an enum, but the enum is used in a runtime context. foo's result is given to a local variable, which does not need to have its value known at compile-time, so foo is not called at compile-time. The fact that the argument to foo is known at compile-time is irrelevant. CTFE is all about evaluating functions at compile-time when the result is used in a context that must be known at compile-time. It isn't used in an attempt to optimize code or attempted just because it might work. It's used because a function is called in a context where the result is explicitly used at compile-time. The most common situations would be template arguments and initializing enums, static variables, and member variables. - Jonathan M Davis
Re: Enum and CTFE function call
On Tuesday, 14 August 2018 at 09:17:41 UTC, ixid wrote: On Tuesday, 14 August 2018 at 09:12:30 UTC, ixid wrote: This will not compile as it says n is not known at compile time... This does work if 'value' is changed to immutable and fun to accept it. So it still seems like a missed opportunity as enum shouldn't be able to change either. If 'value' is a global immutable, its value is known at compile-time, and is equivalent to an enum except you can get its address. If it's passed in a compile-time-compatible way (generally, as a template parameter), it can thus be used as a compile-time constant. Now, as for your initial post: CTFE is run-time code, run at compile-time. In other words, for a function to be CTFE-able, it must be possible to run at run-time, and any compile-time arguments must be passed in a compile-time-compatible way. Your function 'fun' will not compile, because for it to run at run-time, 'n' will need to be known. H. S. Teoh has a great article on the wiki explaining the different stages of compilation in D, which I think would be a great help in your understanding of the differences: https://wiki.dlang.org/User:Quickfur/Compile-time_vs._compile-time -- Simen
Re: Enum and CTFE function call
On Tuesday, August 14, 2018 3:12:30 AM MDT ixid via Digitalmars-d-learn wrote: > This will not compile as it says n is not known at compile time: > > auto fun(int n) { > static foreach(i;0..n) > mixin(i.to!string ~ ".writeln;"); > return; > } > > enum value = 2; > > > void main() { > fun(value); > } > > But making it a template parameter fun(int n)() and fun!value > will obviously work as will replacing n in the foreach statement > with the enum 'value'. It seems like a missed opportunity that > the enum nature of 'value' does not propagate through the > function call letting the compiler know that 'value'and therefore > n are known at compile time. The fact that value is an enum is irrelevant. fun(value) is a call at runtime. CTFE is only triggered if the result must be known at compile time. So, no matter what you pass to fun, fun is not going to be called at compile-time unless the result is required at compile-time - e.g. if it's used to initialize an enum, static variable, or member variable, or if it's used as a template argument. Inside of fun, n is used as in static foreach, which won't work regardless of whether fun is called at compile-time or not, because n is a function argument, not a template argument and is thus a "runtime" value even if the functions is called at compile-time. If you want n to be usable in the static foreach, then it cannot be a function parameter. If it's an argument to the function, it must be a template argument. I suggest that you read this article: https://wiki.dlang.org/User:Quickfur/Compile-time_vs._compile-time It's a work in progress, but it should give you some insight into CTFE. - Jonathan M Davis
Re: Enum and CTFE function call
On Tuesday, 14 August 2018 at 09:17:41 UTC, ixid wrote: On Tuesday, 14 August 2018 at 09:12:30 UTC, ixid wrote: This will not compile as it says n is not known at compile time... This does work if 'value' is changed to immutable and fun to accept it. So it still seems like a missed opportunity as enum shouldn't be able to change either. From the examples on this page: https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe It looks to me like it might be a slight issue with the function being void, in that you need to explicitly ensure that n is immutable. For the example on the page above, they assign the result of the function to a static variable, and so the function is evaluated at compile-time, but without assigning the value to a static variable, it is evaluated at runtime. I guess in this case the compiler may just be being cautious? The page does state that enums should trigger CTFE though.
Re: Enum and CTFE function call
On Tuesday, 14 August 2018 at 09:12:30 UTC, ixid wrote: This will not compile as it says n is not known at compile time... This does work if 'value' is changed to immutable and fun to accept it. So it still seems like a missed opportunity as enum shouldn't be able to change either.
Enum and CTFE function call
This will not compile as it says n is not known at compile time: auto fun(int n) { static foreach(i;0..n) mixin(i.to!string ~ ".writeln;"); return; } enum value = 2; void main() { fun(value); } But making it a template parameter fun(int n)() and fun!value will obviously work as will replacing n in the foreach statement with the enum 'value'. It seems like a missed opportunity that the enum nature of 'value' does not propagate through the function call letting the compiler know that 'value'and therefore n are known at compile time.
Re: Importing struct
On Monday, 13 August 2018 at 14:30:36 UTC, Timoses wrote: On Monday, 13 August 2018 at 14:16:47 UTC, Mike Parker wrote: On Monday, 13 August 2018 at 13:09:24 UTC, Andrey wrote: [...] The convention is to use lowercase for the module name: module myclass; struct MyClass {} Using lowercase letters for module names (and their respective file names!!) also prevents weird errors when different OSes treat lower/capital case letters differently which can sometimes lead to modules not being found. So from my experience: always use lower-case letters for modules and the file names. I understood, thank you!