Re: dlang.org/spec/function.html#pure-functions example
On Monday, 16 October 2023 at 18:05:04 UTC, Paul wrote: On Thursday, 12 October 2023 at 21:20:44 UTC, Jonathan M Davis wrote: look like? Types can have static members. Basically what it comes down to is that outside of immutable data, pure functions only have access to their arguments and to what they can access via their arguments (be it by getting pointers from those arguments or calling other pure functions on them). - Jonathan M Davis Can I say in the general sense that when the word static is used it means that something is defined/declared at compile time? This link should describe all the uses of `static`: https://dlang.org/spec/attribute.html#static
Re: dlang.org/spec/function.html#pure-functions example
On Monday, October 16, 2023 12:05:04 PM MDT Paul via Digitalmars-d-learn wrote: > On Thursday, 12 October 2023 at 21:20:44 UTC, Jonathan M Davis > > wrote: > > look like? > > > > Types can have static members. > > > > Basically what it comes down to is that outside of immutable > > data, pure functions only have access to their arguments and to > > what they can access via their arguments (be it by getting > > pointers from those arguments or calling other pure functions > > on them). > > > > - Jonathan M Davis > > Can I say in the general sense that when the word static is used > it means that something is defined/declared at compile time? Hmmm. It seems like my message got eaten. So, I'll write it out again. In any case, no, in general, static really doesn't have much to with runtime vs compile time. It means different things in different contexts. Off the top of my head, the only contexts where static specifically has anything to do with compile time are with static if and static foreach, in which case, those constructs become compile-time constructs instead of runtime constructos. Other contexts have very different meanings for static. For instance, a static member function is a member function that doesn't have an implicit this reference/pointer and thus is pretty much just a function that's scoped to the class/struct rather than being a function that operates on instances of that class or struct. On the other hand, static member variables are variables which are associated with the class or struct and not with an instance of that class or struct. So, there is only one instance of that variable for all objects of that class or struct on a single thread, as opposed to non-static member variables which are specific to each object. static in functions has similar but different meanings. On a nested function, it makes it so that the function has no implicit parameter which is a reference to the context of the outer function, meaning that it's pretty much just a function within another function, whereas a non-static nested function actually has access to the outer function's scope and thus can access the variables in the outer scope. On the other hand, a static variable within a function is a variable where there is only one instance of that variable for every call to that function on a single thread, as opposed to normal function variables which get a new instance every time that the function is called. And there are other meanings for static in other contexts. There are similarities between them, but if there is a definition that can be given for what static means which covers all of those contexts (and there may be - C manages that in spite of the fact that static means very different things in different contexts there too), it's not an obvious definition. You mostly just have to learn what static means in each context that it's used rather than memorizing a general definition for it that can be applied in each context. - Jonathan M Davis
Re: dlang.org/spec/function.html#pure-functions example
On Monday, October 16, 2023 12:05:04 PM MDT Paul via Digitalmars-d-learn wrote: > On Thursday, 12 October 2023 at 21:20:44 UTC, Jonathan M Davis > > wrote: > > look like? > > > > Types can have static members. > > > > Basically what it comes down to is that outside of immutable > > data, pure functions only have access to their arguments and to > > what they can access via their arguments (be it by getting > > pointers from those arguments or calling other pure functions > > on them). > > > > - Jonathan M Davis > > Can I say in the general sense that when the word static is used > it means that something is defined/declared at compile time?
Re: dlang.org/spec/function.html#pure-functions example
On Thursday, 12 October 2023 at 21:20:44 UTC, Jonathan M Davis wrote: look like? Types can have static members. Basically what it comes down to is that outside of immutable data, pure functions only have access to their arguments and to what they can access via their arguments (be it by getting pointers from those arguments or calling other pure functions on them). - Jonathan M Davis Can I say in the general sense that when the word static is used it means that something is defined/declared at compile time?
Re: dlang.org/spec/function.html#pure-functions example
On Thursday, 12 October 2023 at 21:20:44 UTC, Jonathan M Davis wrote: Thanks Jonathan
Re: dlang.org/spec/function.html#pure-functions example
On Thursday, 12 October 2023 at 19:33:32 UTC, Paul wrote: If **int x** is global mutable state, what does static mutable state look like? In addition to Jonathan's reply, see: https://dlang.org/spec/function.html#local-static-variables
Re: dlang.org/spec/function.html#pure-functions example
On Thursday, October 12, 2023 1:33:32 PM MDT Paul via Digitalmars-d-learn wrote: > The spec doc has the following statement and corresponding > example: > ***"Pure functions cannot directly access global or static > mutable state."*** > > ```d > int x; > immutable int y; > > pure int foo(int i) > { > i++; // ok, modifying local state > //x = i; // error, modifying global state > //i = x; // error, reading mutable global state > i = y; // ok, reading immutable global state > throw new Exception("failed"); // ok > } > ``` > If **int x** is global mutable state, what does static mutable > state look like? Types can have static members. Basically what it comes down to is that outside of immutable data, pure functions only have access to their arguments and to what they can access via their arguments (be it by getting pointers from those arguments or calling other pure functions on them). - Jonathan M Davis
Re: Why is GC.collect `pure`
On Wednesday, August 2, 2023 12:02:35 PM MDT Nick Treleaven via Digitalmars-d- learn wrote: > On Wednesday, 2 August 2023 at 17:55:12 UTC, Nick Treleaven wrote: > > On Wednesday, 2 August 2023 at 17:52:00 UTC, Nick Treleaven > > > > wrote: > >> Now I'm wondering why those functions are marked `pure` - they > >> must affect the GC's bookkeeping state. > > I guess it was because the GC's internal state is not supposed to > be observable outside internal GC functions. I find it harder to > accept some of those than `GC.malloc` being pure, because > GC.disable and GC.enable will affect how long future allocations > will take. That latency can be significant and observed by the > program. Also conceptually they are changing GC state. Well, affecting how long something takes doesn't have anything to do with pure. Another process running on the box could have the same effect. Whether a function can be pure or not is strictly a matter of whether it's possible for it to access any non-immutable data that wasn't passed to it via its arguments. Of course, the whole question of pure gets weird with the GC, because we want to be able to treat GC allocations as pure when in fact they do mutate the GC's state when the GC was not passed in via a function argument. So, when dealing with the GC, purity becomes a question of maintaining the guarantees that the compiler expects with regards to pure and allocations rather than the more straightforward question of whether the function can access any non-immutable data from anything outside of itself via anything other than its arguments. In general, the GC's state is essentially treated as being separate from that of the program itself and thus irrelevant to stuff like pure. As far as the state of the program itself is concerned, the GC could allocate with new and then never bother to free anything, or it could be running a collection every single time new is called - or anything in between. As far as D is concerned, none of that matters to the state of the actual program. It's just a GC concern. That being said, of course, we do need to be careful when dealing directly with GC functions, because we don't want what the compiler does based on pure to end up having undesirable side effects with regards to the GC. As such, whenever deciding whether such functions can be pure or not, we need to carefully consider what the compiler will potentially do based on pure. So, remember that the most that the compiler will do with pure is optimize out multiple calls to the same strongly pure function within a single expression where each call has the exact same arguments. The compiler will also use that information to determine whether a value might be unique or not so that it can determine whether it's safe to convert mutable data to immutable, but that's primarily a type system concern rather than a runtime one. As such, the question of whether it's safe to make a GC function pure essentially comes down to the question of what would happen if you have an expression such as foo(12) * foo(12) which ends up being optimized down to one call to foo instead of two, because foo is strongly pure. And remember that because foo is strongly pure, its arguments are immutable (or were implicitly converted to immutable), and thus its execution in both cases would be identical. So, the exact same sequence of calls to GC functions would occur in each call to foo. So, we don't have to worry about something like the GC being enabled in one call to foo but disabled in the other. The functions that you referred to were GC.collect, GC. minimize, GC.enable, and GC.disable. So, the question becomes how (if at all) it affects the state of the program itself if the number of calls to those functions changes due to a call to foo being optimized out. And it shouldn't take much to see that it doesn't matter. Calling enable or disable multiple times in a row would just result in extraneous calls that do nothing, so optimizing that down to a single call wouldn't matter. Calling minimize multiple times would similarly not matter at all. It's highly unlikely that multiple calls to minimize within a short period of time would make any difference over a single call, and even if it did, it would just be affecting how much free memory the GC had. It would have no effect on the state of the program itself (and remember that as far as the rest of the program is concerned, the state of the GC doesn't even exist; the program's semantics would be the same even if new always grabbed more memory from the OS, and collections never did anything). Now, GC.collect is a bigger question, because that can affect when objects are actually destroyed, which obviously can affect the state of the program outside of the GC based on what the destructors involved do. So, that _can_ affect the program outside of memory allocations. However, when that happens is already effect
Re: Why is GC.collect `pure`
On Wednesday, 2 August 2023 at 17:55:12 UTC, Nick Treleaven wrote: On Wednesday, 2 August 2023 at 17:52:00 UTC, Nick Treleaven wrote: Now I'm wondering why those functions are marked `pure` - they must affect the GC's bookkeeping state. I guess it was because the GC's internal state is not supposed to be observable outside internal GC functions. I find it harder to accept some of those than `GC.malloc` being pure, because GC.disable and GC.enable will affect how long future allocations will take. That latency can be significant and observed by the program. Also conceptually they are changing GC state.
Re: Why is GC.collect `pure`
On Wednesday, 2 August 2023 at 17:52:00 UTC, Nick Treleaven wrote: Now I'm wondering why those functions are marked `pure` - they must affect the GC's bookkeeping state. Here's the pull that added it: https://github.com/dlang/druntime/pull/3561
Re: Pure D frontend as library.
On Tuesday, 27 December 2022 at 12:22:45 UTC, Johan wrote: does semantic analysis (create AST; note that there is a ton of calls needed to complete SeMa), and finally outputs object code. If you want to capitalize the word use SemA. ;)
Re: Pure D frontend as library.
On Monday, 26 December 2022 at 19:13:01 UTC, Alexandru Ermicioi wrote: Hi team, I'd like to ask a lazy question: How easy is to use D compiler frontend without backend? How complicated would be to write a transpiler, and from which files should you start modifications? I'm wondering if something like https://typescripttolua.github.io/ could be done, but with d as language. From my limited knowledge, I should have an AST visitor that transpiles to target language, and some entry point for application which configures D frontend to use my AST visitor to generate code. I've no idea from where to start. If you know some documentation or tutorials, that would be appreciated. You can have a look at LDC's code, which does what you are saying. LDC first initializes itself (`cppmain()`) and then calls `mars_mainBody` (https://github.com/ldc-developers/ldc/blob/e5c97c6468334c65130a654c8aec819c51dd61d3/dmd/mars.d#L197) which reads source code files, does semantic analysis (create AST; note that there is a ton of calls needed to complete SeMa), and finally outputs object code. I'd start by copying the initialization and SeMa parts and stopping before the codegen part, removing all things that you think you will not need. The difficult thing is interpreting the AST. LDC does not use a visitor, don't get stuck on that idea, you don't necessarily need it. Documentation of the AST is not great; to discover what things mean / what needs to be done, consult the handling of AST nodes by LDC or DMD's glue layers. Of course you don't have to implement everything at the start. Just get function definitions, function calls, and string definitions going first --> that's what your "hello world" needs ;) I have never looked at GDC's code, but I presume it is quite similar in this regard to LDC, so you can look at that too. -Johan
Re: Pure D frontend as library.
On 27/12/2022 9:34 PM, Alexandru Ermicioi wrote: Any idea from which file should I start at least learning about this glue code? You can look at dmd's... but realistically the work hasn't been done at that level to make it easy to work with. https://github.com/dlang/dmd/blob/master/compiler/src/dmd/glue.d https://github.com/dlang/dmd/blob/master/compiler/src/dmd/gluelayer.d Note how it doesn't let you use your own implementation. This is very much throwing you into the deep end without any help.
Re: Pure D frontend as library.
On Monday, 26 December 2022 at 23:08:59 UTC, Richard (Rikki) Andrew Cattermole wrote: ... That on the other hand... Yeah, things aren't great on that front. The thing you want to implement is what we call glue code and isn't really setup right now for this (nobody has tried like this, ignoring ldc/gdc as they modify it). Hi, thx for information. Any idea from which file should I start at least learning about this glue code? Also, since this is not yet done, is there a way to insert this custom glue code without modifying D frontend source code? If not which file should I register custom changes? Thanks, Alexandru.
Re: Pure D frontend as library.
On 27/12/2022 8:13 AM, Alexandru Ermicioi wrote: How easy is to use D compiler frontend without backend? Easy. https://github.com/dlang/dmd/blob/master/compiler/test/dub_package/frontend.d How complicated would be to write a transpiler, and from which files should you start modifications? That on the other hand... Yeah, things aren't great on that front. The thing you want to implement is what we call glue code and isn't really setup right now for this (nobody has tried like this, ignoring ldc/gdc as they modify it).
Pure D frontend as library.
Hi team, I'd like to ask a lazy question: How easy is to use D compiler frontend without backend? How complicated would be to write a transpiler, and from which files should you start modifications? I'm wondering if something like https://typescripttolua.github.io/ could be done, but with d as language. From my limited knowledge, I should have an AST visitor that transpiles to target language, and some entry point for application which configures D frontend to use my AST visitor to generate code. I've no idea from where to start. If you know some documentation or tutorials, that would be appreciated. Thanks, Alexandru.
Re: how to benchmark pure functions?
On Thursday, 27 October 2022 at 18:41:36 UTC, Dennis wrote: On Thursday, 27 October 2022 at 17:17:01 UTC, ab wrote: How can I prevent the compiler from removing the code I want to measure? With many C compilers, you can use volatile assembly blocks for that. With LDC -O3, a regular assembly block also does the trick currently: ```D void main() { import std.datetime.stopwatch; import std.stdio: write, writeln, writef, writefln; import std.conv : to; void f0() {} void f1() { foreach(i; 0..4_000_000) { // nothing, loop gets optimized out } } void f2() { foreach(i; 0..4_000_000) { // defeat optimizations asm @safe pure nothrow @nogc {} } } auto r = benchmark!(f0, f1, f2)(1); writeln(r[0]); // 4 μs writeln(r[1]); // 4 μs writeln(r[2]); // 1 ms } ``` I recommend a volatile data dependency rather than injecting volatile ASM into code FYI i.e. don't modify the pure function but rather make sure the result is actually used in the eyes of the compiler.
Re: how to benchmark pure functions?
On Friday, 28 October 2022 at 09:48:14 UTC, ab wrote: Thanks to H.S. Teoh and Dennis for the suggestions, they both work. I like the empty asm block a bit more because it is less invasive, but it only works with ldc. I used the volatileLoad/volatileStore functions to ensure that the compiler doesn't find a way to optimize out the code (for example, move repetitive calculations out of the loop or even do them at compile time) and the RDTSC/RDTSCP instruction via inline assembly for measurements: https://gist.github.com/ssvb/5c926ed9bc755900fdaac3b71a0f7cfd The goal was to have a very fast way to check (with no measurable overhead) whether reasonable optimization options had been supplied to the compiler.
Re: how to benchmark pure functions?
On Friday, 28 October 2022 at 09:48:14 UTC, ab wrote: On Thursday, 27 October 2022 at 17:17:01 UTC, ab wrote: [...] Thanks to H.S. Teoh and Dennis for the suggestions, they both work. I like the empty asm block a bit more because it is less invasive, but it only works with ldc. @Imperatorn see Dennis code for an example. std.datetime.benchmark works, but at high optimization level (-O2, -O3) the loop can be removed and the time brought down to 0hnsec. E.g. try "ldc2 -O3 -run dennis.d". AB Yeah I didn't read carefully enough sorry
Re: how to benchmark pure functions?
On Thursday, 27 October 2022 at 17:17:01 UTC, ab wrote: Hi, when trying to compare different implementations of the optimized builds of a pure function using benchmark from std.datetime.stopwatch, I get times equal to zero, I suppose because the functions are not executed as they do not have side effects. The same happens with the example from the documentation: https://dlang.org/library/std/datetime/stopwatch/benchmark.html How can I prevent the compiler from removing the code I want to measure? Is there some utility in the standard library or pragma that I should use? Thanks AB Thanks to H.S. Teoh and Dennis for the suggestions, they both work. I like the empty asm block a bit more because it is less invasive, but it only works with ldc. @Imperatorn see Dennis code for an example. std.datetime.benchmark works, but at high optimization level (-O2, -O3) the loop can be removed and the time brought down to 0hnsec. E.g. try "ldc2 -O3 -run dennis.d". AB
Re: how to benchmark pure functions?
On Thursday, 27 October 2022 at 17:17:01 UTC, ab wrote: How can I prevent the compiler from removing the code I want to measure? With many C compilers, you can use volatile assembly blocks for that. With LDC -O3, a regular assembly block also does the trick currently: ```D void main() { import std.datetime.stopwatch; import std.stdio: write, writeln, writef, writefln; import std.conv : to; void f0() {} void f1() { foreach(i; 0..4_000_000) { // nothing, loop gets optimized out } } void f2() { foreach(i; 0..4_000_000) { // defeat optimizations asm @safe pure nothrow @nogc {} } } auto r = benchmark!(f0, f1, f2)(1); writeln(r[0]); // 4 μs writeln(r[1]); // 4 μs writeln(r[2]); // 1 ms } ```
Re: how to benchmark pure functions?
On Thu, Oct 27, 2022 at 06:20:10PM +, Imperatorn via Digitalmars-d-learn wrote: > On Thursday, 27 October 2022 at 17:17:01 UTC, ab wrote: > > Hi, > > > > when trying to compare different implementations of the optimized > > builds of a pure function using benchmark from > > std.datetime.stopwatch, I get times equal to zero, I suppose because > > the functions are not executed as they do not have side effects. > > > > The same happens with the example from the documentation: > > https://dlang.org/library/std/datetime/stopwatch/benchmark.html > > > > How can I prevent the compiler from removing the code I want to > > measure? Is there some utility in the standard library or pragma > > that I should use? [...] To prevent the optimizer from eliding the function completely, you need to do something with the return value. Usually, this means you combine the return value into some accumulating variable, e.g., if it's an int function, have a running int accumulator that you add to: int funcToBeMeasured(...) pure { ... } int accum; auto results = benchmark!({ // Don't just call funcToBeMeasured and ignore the value // here, otherwise the optimizer may delete the call // completely. accum += funcToBeMeasured(...); }); Then at the end of the benchmark, do something with the accumulated value, like print out its value to stdout, so that the optimizer doesn't notice that the value is unused, and decide to kill all previous assignments to it. Something like `writeln(accum);` at the end should do the trick. T -- Indifference will certainly be the downfall of mankind, but who cares? -- Miquel van Smoorenburg
Re: how to benchmark pure functions?
On Thursday, 27 October 2022 at 17:17:01 UTC, ab wrote: Hi, when trying to compare different implementations of the optimized builds of a pure function using benchmark from std.datetime.stopwatch, I get times equal to zero, I suppose because the functions are not executed as they do not have side effects. The same happens with the example from the documentation: https://dlang.org/library/std/datetime/stopwatch/benchmark.html How can I prevent the compiler from removing the code I want to measure? Is there some utility in the standard library or pragma that I should use? Thanks AB Sorry, I don't understand what you're saying. The examples work for me. Can you provide an exact code example which does not work as expected for you?
how to benchmark pure functions?
Hi, when trying to compare different implementations of the optimized builds of a pure function using benchmark from std.datetime.stopwatch, I get times equal to zero, I suppose because the functions are not executed as they do not have side effects. The same happens with the example from the documentation: https://dlang.org/library/std/datetime/stopwatch/benchmark.html How can I prevent the compiler from removing the code I want to measure? Is there some utility in the standard library or pragma that I should use? Thanks AB
Re: What is pure used for?
On Thursday, 25 November 2021 at 07:26:48 UTC, sclytrack wrote: int * pureFunction() 1) the pointer needs to be the same. 2) the value that the pointer points to needs to be the same. I call this the "value of interest" with relation to pure. The pointer doesn't matter. 3) both the pointer and the value the pointer is pointing too needs to be the same. pureCalloc() satisfies (2) pureMalloc() violates everything. There is a special case in the language spec to allow functions like `pureMalloc`. They are called "pure factory functions": A *pure factory function* is a strongly pure function that returns a result that has mutable indirections. All mutable memory returned by the call may not be referenced by any other part of the program, i.e. it is newly allocated by the function. Nor may the mutable references of the result refer to any object that existed before the function call. Source: <https://dlang.org/spec/function.html#pure-functions> (scroll down) Does the D compiler do any optimizations? Yes, but those optimizations may result in implementation-defined behavior: **Implementation Defined:** An implementation may assume that a strongly pure function that returns a result without mutable indirections will have the same effect for all invocations with equivalent arguments. It is allowed to memoize the result of the function under the assumption that equivalent parameters always produce equivalent results. [...] An implementation is currently not required to enforce validity of memoization in all cases. The term "equivalent" is not explicitly defined, but as far as I can tell it means something like item (2) in your list.
Re: What is pure used for?
On Thursday, 25 November 2021 at 07:26:48 UTC, sclytrack wrote: My understanding is that pure is used for compiler optimization in loops and expressions. It leaves out multiple calls if it figures out it is not needed. [one link](https://klickverbot.at/blog/2012/05/purity-in-d/#indirections-in-the-return-type) and [another](https://theartofmachinery.com/2016/03/28/dirtying_pure_functions_can_be_useful.html)
Re: What is pure used for?
On Thursday, 25 November 2021 at 07:26:48 UTC, sclytrack wrote: My understanding is that pure is used for compiler optimization in loops and expressions. It leaves out multiple calls if it figures out it is not needed. Is pure used for anything else? int * pureFunction() 1) the pointer needs to be the same. 2) the value that the pointer points to needs to be the same. I call this the "value of interest" with relation to pure. The pointer doesn't matter. 3) both the pointer and the value the pointer is pointing too needs to be the same. pureCalloc() satisfies (2) pureMalloc() violates everything. Does the D compiler do any optimizations? https://dlang.org/spec/function.html#pure-functions
What is pure used for?
My understanding is that pure is used for compiler optimization in loops and expressions. It leaves out multiple calls if it figures out it is not needed. Is pure used for anything else? int * pureFunction() 1) the pointer needs to be the same. 2) the value that the pointer points to needs to be the same. I call this the "value of interest" with relation to pure. The pointer doesn't matter. 3) both the pointer and the value the pointer is pointing too needs to be the same. pureCalloc() satisfies (2) pureMalloc() violates everything. Does the D compiler do any optimizations?
Re: cast to pure function stop work after upgrade
On Monday, 2 August 2021 at 15:10:06 UTC, vit wrote: On Monday, 2 August 2021 at 11:28:46 UTC, Tejas wrote: [...] Try this: ```d void main(){ fp = cast(typeof(fp)) //fails } ``` Agh, stupid me. You the man!!
Re: cast to pure function stop work after upgrade
On Monday, 14 June 2021 at 13:31:51 UTC, baby_tiger wrote: this used work for me, after upgrade I get this error. how to fix it ? import std.traits; enum LogLevel : ubyte { INFO = 0, WARN, ERROR, FATAL, } extern (C) string VFORMAT(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow { return null; } template asPure(string P, alias Fn) if (isFunctionPointer!(typeof())) { enum N = __traits(identifier, Fn); enum string asPure = "private alias " ~ N ~ "_PURE = " ~ typeof().stringof ~ " pure;\n" ~ "__gshared immutable " ~ N ~ "_PURE " ~ P ~"= cast(" ~ N ~ "_PURE) &" ~ N ~ " ;" ; } enum xx = asPure!("VFORMATP", VFORMAT); mixin(xx); void main(){ } reinterpreting cast from `nothrow @nogc extern (C) string(LogLevel level, string file, ulong line, char[] tmp, bool line_break, string tag, string fmt, ...)*` to `pure nothrow @nogc extern (C) string(LogLevel, string, ulong, char[], bool, string, string, ...)*` is not supported in CTFE ```d int foo(int x)@safe{ return x; } /* This is valid. @safe CTFE cast, systemFoo has less restrictive function type. */ auto systemFoo = cast(int function(int)@system) /* ERROR UNSAFE CTFE cast, pureFoo has more restrictive function type. */ //auto pureFoo = cast(void function(int)pure) int function(int)pure pureFoo; shared static this(){ /* This is valid. UNSAFE RUNTIME cast. */ pureFoo = cast(int function(int)pure) } void main(){ assert(pureFoo(42) == 42); } ```
Re: cast to pure function stop work after upgrade
On Monday, 2 August 2021 at 11:28:46 UTC, Tejas wrote: On Monday, 14 June 2021 at 13:31:51 UTC, baby_tiger wrote: [...] It seems to not work at runtime either. Maybe they've made this behaviour illegal now? Hopefully someone answers. ```d import std.traits; import core.stdc.stdarg; enum LogLevel : ubyte { INFO = 0, WARN, ERROR, FATAL, } extern (C) string VFORMAT(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow { return null; } extern (C) string function(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow pure fp; void main(){ fp = //fails } ``` Try this: ```d void main(){ fp = cast(typeof(fp)) //fails } ```
Re: cast to pure function stop work after upgrade
On Monday, 14 June 2021 at 13:31:51 UTC, baby_tiger wrote: this used work for me, after upgrade I get this error. how to fix it ? import std.traits; enum LogLevel : ubyte { INFO = 0, WARN, ERROR, FATAL, } extern (C) string VFORMAT(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow { return null; } template asPure(string P, alias Fn) if (isFunctionPointer!(typeof())) { enum N = __traits(identifier, Fn); enum string asPure = "private alias " ~ N ~ "_PURE = " ~ typeof().stringof ~ " pure;\n" ~ "__gshared immutable " ~ N ~ "_PURE " ~ P ~"= cast(" ~ N ~ "_PURE) &" ~ N ~ " ;" ; } enum xx = asPure!("VFORMATP", VFORMAT); mixin(xx); void main(){ } reinterpreting cast from `nothrow @nogc extern (C) string(LogLevel level, string file, ulong line, char[] tmp, bool line_break, string tag, string fmt, ...)*` to `pure nothrow @nogc extern (C) string(LogLevel, string, ulong, char[], bool, string, string, ...)*` is not supported in CTFE It seems to not work at runtime either. Maybe they've made this behaviour illegal now? Hopefully someone answers. ```d import std.traits; import core.stdc.stdarg; enum LogLevel : ubyte { INFO = 0, WARN, ERROR, FATAL, } extern (C) string VFORMAT(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow { return null; } extern (C) string function(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow pure fp; void main(){ fp = //fails } ```
cast to pure function stop work after upgrade
this used work for me, after upgrade I get this error. how to fix it ? import std.traits; enum LogLevel : ubyte { INFO = 0, WARN, ERROR, FATAL, } extern (C) string VFORMAT(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow { return null; } template asPure(string P, alias Fn) if (isFunctionPointer!(typeof())) { enum N = __traits(identifier, Fn); enum string asPure = "private alias " ~ N ~ "_PURE = " ~ typeof().stringof ~ " pure;\n" ~ "__gshared immutable " ~ N ~ "_PURE " ~ P ~"= cast(" ~ N ~ "_PURE) &" ~ N ~ " ;" ; } enum xx = asPure!("VFORMATP", VFORMAT); mixin(xx); void main(){ } reinterpreting cast from `nothrow @nogc extern (C) string(LogLevel level, string file, ulong line, char[] tmp, bool line_break, string tag, string fmt, ...)*` to `pure nothrow @nogc extern (C) string(LogLevel, string, ulong, char[], bool, string, string, ...)*` is not supported in CTFE
Re: GC.addRange in pure function
On Friday, 12 February 2021 at 12:17:13 UTC, Per Nordlöw wrote: On Tuesday, 9 February 2021 at 03:05:10 UTC, frame wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? Would making `new T[]` inject a call to `GC.addRange` based on `T` (and maybe also T's attributes) be a step forward? `GC.addRange` is only used for memory allocated outside of the GC that can hold references to GC allocated objects. Since `new T[]` uses the GC, all the information is typeinfo is already there (*), so `GC.addRange` is unnecessary and even wrong, because when the GC collects the memory it won't call `GC.removeRange` on it Implementation-wise, metadata about GC-allocated memory is held in the GC internal data structures, whereas the GC roots and ranges are stored in separate malloc/free-managed containers. (*) Currently `new T[]` is lowered to an `extern (C)` runtime hook and the compiler passes to it typeid(T). After this the call chain is: _d_newarray_d_newarray{T,iT,mTX,miTX} -> _d_newarrayU -> __arrayAlloc -> GC.qalloc -> ConservativeGC.mallocNoSync -> Gcx.alloc -> {small,big}Alloc -> setBits
Re: GC.addRange in pure function
On Friday, 12 February 2021 at 19:48:01 UTC, vitamin wrote: On Wednesday, 10 February 2021 at 16:25:44 UTC, Petar Kirov [ZombineDev] wrote: On Wednesday, 10 February 2021 at 13:44:53 UTC, vit wrote: [...] TL;DR Yes, you can, but it depends on what "without problem" means for you :P [...] Thanks, Yes, I am implementing container (ref counted pointer). When allcoator is Mallcoator (pure allocate and deallocate) and constructor of Type inside rc pointer has pure constructor and destructor, then only impure calls was GC.addRange and GC.removeRange. Now there are marked as pure. Great, that's the exact idea!
Re: GC.addRange in pure function
On Wednesday, 10 February 2021 at 16:25:44 UTC, Petar Kirov [ZombineDev] wrote: On Wednesday, 10 February 2021 at 13:44:53 UTC, vit wrote: [...] TL;DR Yes, you can, but it depends on what "without problem" means for you :P [...] Thanks, Yes, I am implementing container (ref counted pointer). When allcoator is Mallcoator (pure allocate and deallocate) and constructor of Type inside rc pointer has pure constructor and destructor, then only impure calls was GC.addRange and GC.removeRange. Now there are marked as pure.
Re: GC.addRange in pure function
On Tuesday, 9 February 2021 at 03:05:10 UTC, frame wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? Would making `new T[]` inject a call to `GC.addRange` based on `T` (and maybe also T's attributes) be a step forward?
Re: GC.addRange in pure function
On Wednesday, 10 February 2021 at 16:25:44 UTC, Petar Kirov [ZombineDev] wrote: [..] A few practical examples: Here it is deemed that the only observable side-effect of `malloc` and friends is the setting of `errno` in case of failure, so these wrappers ensure that this is not observed. Surely there are low-level ways to observe it (and also the act of allocating / deallocating memory on the C heap), but this definition purity what the standard library has decided it was reasonable: https://github.com/dlang/druntime/blob/master/src/core/memory.d#L1082-L1150 These two function calls in Array.~this() can be marked as `pure`, as the Array type as a whole implements the RAII design pattern and offers at least basic exception-safety guarantees: https://github.com/dlang/phobos/blob/81a968dee68728f7ea245b6983eb7236fb3b2981/std/container/array.d#L296-L298 (The whole function is not marked pure, as the purity depends on the purity of the destructor of the template type parameter `T`.)
Re: GC.addRange in pure function
On Wednesday, 10 February 2021 at 13:44:53 UTC, vit wrote: On Wednesday, 10 February 2021 at 12:17:43 UTC, rm wrote: On 09/02/2021 5:05, frame wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? Does 'new' violate the 'pure' paradigm? Pure functions can only call pure functions and GC.addRange or GC.removeRange is only 'nothrow @nogc'. new allocates memory via the GC and the GC knows to scan this location. Seems like implicit GC.addRange. Yes, this is my problem, if `new` can create object in pure function, then GC.addRange and GC.removeRange is may be pure too. Can I call GC.addRange and GC.removeRange from pure function without problem? (using assumePure(...)() ). TL;DR Yes, you can, but it depends on what "without problem" means for you :P # The Dark Arts of practical D code === According to D's general approach to purity, malloc/free/GC.* are indeed impure as they read and write global **mutable** state, but are still allowed in pure functions **if encapsulated properly**. The encapsulation is done by @trusted wrappers which must be carefully audited by humans - the compiler can't help you with that. The general rule that you must follow for such *callable-from-pure* code (technically it is labeled as `pure`, e.g.: pragma(mangle, "malloc") pure @system @nogc nothrow void* fakePureMalloc(size_t); but I prefer to make the conceptual distinction) is that the effect of calling the @trusted wrapper must not drastically leak / be observed. What "drastically" means depends on what you want `pure` to mean in your application. Which side-effects you want to protect against by using `pure`? It is really a high-level concern that you as a developer must decide on when writing/using @trusted pure code in your program. For example, generally everyone will agree that network calls are impure. But what about logging? It's impure by definition, since it mutates a global log stream. But is this effect worth caring about? In some specific situations it maybe ok to ignore. This is why in D you can call `writeln` in `pure` functions, as long as it's inside a `debug` block. But given that you as a developer can decide whether to pass `-debug` option to the compiler, essentially you're in control of what `pure` means for your codebase, at least to some extent. 100% mathematical purity is impossible even in the most strict functional programming language implementations, since our programs run on actual hardware and not on an idealized mathematical machine. For example, even the act of reading immutable data can be globally observed as by measuring the memory access times - see Spectre [1] and all other microarchitecture side-channel [1] vulnerabilities. [1]: https://en.wikipedia.org/wiki/Spectre_(security_vulnerability) [2]: https://en.wikipedia.org/wiki/Side-channel_attack That said, function purity is not useless at all, quite the contrary. It is about making your programs more deterministic and easy to reason about. We all want less bugs in our code and less time spent chasing hard to reproduce crashes, right? `pure` is really about limiting, containing / compartmentalizing and controlling the the (in-deterministic) global effects in your program. Ideally you should strive to structure your programs as a pure core, driven by an imperative, impure shell. E.g. if you're working on an accounting application, the core is the part that implements the main domain / business logic and should be 100% deterministic and pure. The imperative shell is the part that reads spreadsheet files, exports to pdf, etc. (actually just the actual file I/O needs to be impure - the actual decoding / encoding of data structures can be perfectly pure). Now, back to practice and the question of memory management. Of course allocating memory is globally observable effect and even locally one can compare pointers, as Paul Backus mentioned, as D is a systems language. However, as a practical concession, D's concept of pure-ity is about ensuring high-level invariants and so such low-level concerns can be ignored, as long as the codebase doesn't observe them. What does it mean to observe them? Here's an example: --- void main() { import std.stdio : writeln; observingLowLevelSideEffects.writeln; // `false`, but could be `true` notObservingSideEffects.writeln; // always `true` } // BAD: bool observingLowLevelSideEffects() pure { immutable a = [2]; immutable b = [2]; return a.ptr == b.ptr; } // OK bool notObservingSideEffects() pure { immutable a = [2]; immutable b = [2]; return a == b; } --- `observingLowLevelSideEffects` is bad, as according to the language rules, the compiler is free to make `a` and `b` point to the same immutable arr
Re: GC.addRange in pure function
On Wednesday, 10 February 2021 at 12:17:43 UTC, rm wrote: On 09/02/2021 5:05, frame wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? Does 'new' violate the 'pure' paradigm? Pure functions can only call pure functions and GC.addRange or GC.removeRange is only 'nothrow @nogc'. new allocates memory via the GC and the GC knows to scan this location. Seems like implicit GC.addRange. Yes, this is my problem, if `new` can create object in pure function, then GC.addRange and GC.removeRange is may be pure too. Can I call GC.addRange and GC.removeRange from pure function without problem? (using assumePure(...)() ).
Re: GC.addRange in pure function
On 09/02/2021 5:05, frame wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? Does 'new' violate the 'pure' paradigm? Pure functions can only call pure functions and GC.addRange or GC.removeRange is only 'nothrow @nogc'. new allocates memory via the GC and the GC knows to scan this location. Seems like implicit GC.addRange.
Re: GC.addRange in pure function
On Tuesday, 9 February 2021 at 21:00:39 UTC, Paul Backus wrote: On Tuesday, 9 February 2021 at 19:53:27 UTC, Temtaime wrote: pure is broken. Just don't [use it] Allowing memory allocation in pure code in a language that can distinguish between pointer equality and value equality is, let's say, "unprincipled." pure in D is a very useful concept, even if it's not literally the same as pure in functional languages. Recommending not to use it is bad advice IMHO.
Re: GC.addRange in pure function
On Tuesday, 9 February 2021 at 20:50:12 UTC, Max Haughton wrote: On Tuesday, 9 February 2021 at 19:53:27 UTC, Temtaime wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? pure is broken. Just don't [use it] [Citation needed] Allowing memory allocation in pure code in a language that can distinguish between pointer equality and value equality is, let's say, "unprincipled."
Re: GC.addRange in pure function
On Tuesday, 9 February 2021 at 19:53:27 UTC, Temtaime wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? pure is broken. Just don't [use it] [Citation needed]
Re: GC.addRange in pure function
On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? pure is broken. Just don't [use it]
Re: GC.addRange in pure function
On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? Does 'new' violate the 'pure' paradigm? Pure functions can only call pure functions and GC.addRange or GC.removeRange is only 'nothrow @nogc'.
GC.addRange in pure function
Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed?
Re: Escape this in pure members
On 23.09.20 02:06, DlangUser38 wrote: The following analysis might be wrong but I think that `scope` as a **member** function attribute is not supposed to be used as that is not even documented. It's documented here: https://dlang.org/spec/memory-safe-d.html#scope-return-params Quote: "[`scope` and `return`] may appear after the formal parameter list, in which case they apply either to a method's this parameter, or [... irrelevant ...]." It's less than ideal that the documentation of `scope` is spread over two pages.
Re: Escape this in pure members
On Wednesday, 23 September 2020 at 00:06:38 UTC, DlangUser38 wrote: Hmm, why would `b` have longer lifetime? Isn't the lifetime of `b` throughout `bar`? The following analysis might be wrong but I think that `scope` as a **member** function attribute is not supposed to be used as that is not even documented. Where's the other scope analysis documented? So it would works "by default". The compiler thinks that `this` is a scope variable that will stop living after `bar()`. So are you saying that this code should compile with and without the member being `scope`? Also as `b` is not `ref` this is clearly a wrong diagnostic. There's a special case missing in the compiler.
Re: Escape this in pure members
On Tuesday, 22 September 2020 at 18:21:10 UTC, Jacob Carlborg wrote: On 2020-09-19 21:50, Per Nordlöw wrote: On Saturday, 19 September 2020 at 18:48:31 UTC, Jacob Carlborg wrote: A nested class seems to be able to escape the `this` reference: Ahh, thanks. I just realized that it can escape into other parameters without the `scope` qualifier? This class Bar { void bar(scope Bar b) @safe pure { b = this; } } compiles but this class Bar { scope void bar(scope Bar b) @safe pure { b = this; // Error: scope variable `this` assigned to `b` with longer lifetime } } Hmm, why would `b` have longer lifetime? Isn't the lifetime of `b` throughout `bar`? The following analysis might be wrong but I think that `scope` as a **member** function attribute is not supposed to be used as that is not even documented. So it would works "by default". The compiler thinks that `this` is a scope variable that will stop living after `bar()`. Also as `b` is not `ref` this is clearly a wrong diagnostic. There's a special case missing in the compiler.
Re: Escape this in pure members
On 2020-09-19 21:50, Per Nordlöw wrote: On Saturday, 19 September 2020 at 18:48:31 UTC, Jacob Carlborg wrote: A nested class seems to be able to escape the `this` reference: Ahh, thanks. I just realized that it can escape into other parameters without the `scope` qualifier? This class Bar { void bar(scope Bar b) @safe pure { b = this; } } compiles but this class Bar { scope void bar(scope Bar b) @safe pure { b = this; // Error: scope variable `this` assigned to `b` with longer lifetime } } Hmm, why would `b` have longer lifetime? Isn't the lifetime of `b` throughout `bar`? -- /Jacob Carlborg
Re: Escape this in pure members
On Saturday, 19 September 2020 at 18:48:31 UTC, Jacob Carlborg wrote: A nested class seems to be able to escape the `this` reference: Ahh, thanks. I just realized that it can escape into other parameters without the `scope` qualifier? This class Bar { void bar(scope Bar b) @safe pure { b = this; } } compiles but this class Bar { scope void bar(scope Bar b) @safe pure { b = this; // Error: scope variable `this` assigned to `b` with longer lifetime } } fails as foo.d(6,11): Error: scope variable `this` assigned to `b` with longer lifetime
Re: Escape this in pure members
On 2020-09-19 18:07, Per Nordlöw wrote: If an aggregate member is pure but not scope when can it escape the `this` pointer?. Only via return? I'm not sure if returning the `this` pointer is considered escaping it. The caller already had access to it. Under the hood, the `this` pointer is just another argument passed to the function. In the struct and class case? A nested class seems to be able to escape the `this` reference: class Foo { Bar b; class Bar { void bar() pure { b = this; } } } -- /Jacob Carlborg
Re: Escape this in pure members
On Saturday, 19 September 2020 at 16:07:24 UTC, Per Nordlöw wrote: If an aggregate member is pure but not scope when can it escape the `this` pointer?. Or rather when and, if so, how can the member allow its `this` pointer to escape? It seems to me like the `scope` qualifier is no effect in this case.
Escape this in pure members
If an aggregate member is pure but not scope when can it escape the `this` pointer?. Only via return? In the struct and class case?
Re: variant visit not pure?
On Thursday, 7 May 2020 at 20:12:03 UTC, learner wrote: Modules of D standard library aren't in a good shape, if everyone suggests alternatives for a basic building block as variant. I don't think Variant as a whole is the problem, when one uses it as the infinite variant it does fairly much what one can expect. The finite-field specialization of it is the one that's badly implemented. The types VariantN can hold are known at compile time, why can't it be specialized? It could, probably. This shows the biggest weakness (and strength) of D development: It's voluntary, so people work on that they happen to want to. That makes it unevenly developed compared to financially backed projects. We have both plenty of cool & rare features and lack of many relatively basic ones at the same time.
Re: variant visit not pure?
On Thursday, 7 May 2020 at 15:36:36 UTC, Ben Jones wrote: I've been using SumType... What are the main differences between it and TaggedAlgebraic? I have not used the the algebraic type of Taggedalgebraic tbh, but it also has a tagged union type that I have good experiences with. Unlike Phobos algebraic or SumType, it can have multiple fields of same type that are still separate by the tag value. Also unlike the two others I mentioned, you can handily define a `Void` field (or many of them) if you want special values for the tag that don't come with a value. In essence, `Taggedalgebraic.TaggedUnion` it's the D equivalent of Rust `enum`[1]. 1: https://doc.rust-lang.org/book/ch06-00-enums.html
Re: variant visit not pure?
On Thursday, 7 May 2020 at 10:21:26 UTC, Dukc wrote: that's the reason why `std.range.enumerate` does not infer attributes for example This was wrong. `enumerate` can infer. It's `lockstep` that cannot.
Re: variant visit not pure?
On Thursday, 7 May 2020 at 14:53:10 UTC, Steven Schveighoffer wrote: On 5/7/20 5:22 AM, learner wrote: [...] Because VariantN (the base of Algebraic) can literally hold anything, it cannot be pure, @safe, nothrow, @nogc. As others have recommended, I suggest using TaggedAlgebraic. I recently have been using it to create an algebraic type to hold a MYSQL value, so I can migrate the mysql-native library to be @safe (mysql-native currently uses Variant for everything). I added a special UDA to TaggedAlgebraic, so you can guarantee only @safe calls are allowed (for instance, if it can hold a pointer and an int, then opBinary!"+" can be marked as @safe if the operation fails when it's a pointer). TaggedAlgebraic could probably do the same for pure, but not sure about nothrow and @nogc, since it uses exceptions when things aren't valid. -Steve Modules of D standard library aren't in a good shape, if everyone suggests alternatives for a basic building block as variant. The types VariantN can hold are known at compile time, why can't it be specialized?
Re: variant visit not pure?
On Thursday, 7 May 2020 at 15:36:36 UTC, Ben Jones wrote: On Thursday, 7 May 2020 at 14:53:10 UTC, Steven Schveighoffer wrote: As others have recommended, I suggest using TaggedAlgebraic. I recently have been using it to create an algebraic type to hold a MYSQL value, so I can migrate the mysql-native library to be @safe (mysql-native currently uses Variant for everything). -Steve I've been using SumType... What are the main differences between it and TaggedAlgebraic? As far as I can tell, there are two main differences: 1. TaggedAlgebraic has some convenient operator overloads that can assert at runtime if called improperly (i.e., when the contained type does not support the operation). SumType never asserts at runtime, and instead requires you to use `match` for these operations to ensure that they are only performed on the appropriate types. 2. TaggedAlgebraic requires you to declare a union type as a "base", whereas SumType takes the list of member types directly as template arguments. If you want more detailed information, both have online documentation: TaggedAlgebraic: https://vibed.org/api/taggedalgebraic.taggedalgebraic/ SumType: https://pbackus.github.io/sumtype/sumtype.html
Re: variant visit not pure?
On Thursday, 7 May 2020 at 14:53:10 UTC, Steven Schveighoffer wrote: As others have recommended, I suggest using TaggedAlgebraic. I recently have been using it to create an algebraic type to hold a MYSQL value, so I can migrate the mysql-native library to be @safe (mysql-native currently uses Variant for everything). -Steve I've been using SumType... What are the main differences between it and TaggedAlgebraic?
Re: variant visit not pure?
On 5/7/20 5:22 AM, learner wrote: Good morning, Is there a reason why std.variant.visit is not inferring pure? ``` void test() pure { Algebraic!(int, string) alg; visit!( (string) => 0, (int) => 0)(alg); } Error: pure function test cannot call impure function test.visit!(VariantN!(16LU, int, string)).visit ``` Thank you Because VariantN (the base of Algebraic) can literally hold anything, it cannot be pure, @safe, nothrow, @nogc. As others have recommended, I suggest using TaggedAlgebraic. I recently have been using it to create an algebraic type to hold a MYSQL value, so I can migrate the mysql-native library to be @safe (mysql-native currently uses Variant for everything). I added a special UDA to TaggedAlgebraic, so you can guarantee only @safe calls are allowed (for instance, if it can hold a pointer and an int, then opBinary!"+" can be marked as @safe if the operation fails when it's a pointer). TaggedAlgebraic could probably do the same for pure, but not sure about nothrow and @nogc, since it uses exceptions when things aren't valid. -Steve
Re: variant visit not pure?
On Thursday, 7 May 2020 at 13:17:21 UTC, learner wrote: I've find this: https://issues.dlang.org/show_bug.cgi?id=16662 Hmm, that explains why it can't infer attributes. An unlimited variant could contain an object, and using it might or might not be . Of course, it could still infer the attribute for algebraic types were the wrapper a bit smarter. But `Algebraic` is inferior to the DUB packages anyway. Bad performance like Simen said, and can always be `null` regardless of requested types. With Taggedalgebraic, you can insert `Void` to allowed types if you want `null` value but you don't have it just because.
Re: variant visit not pure?
On Thursday, 7 May 2020 at 10:41:01 UTC, Simen Kjærås wrote: On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote: Good morning, Is there a reason why std.variant.visit is not inferring pure? ``` void test() pure { Algebraic!(int, string) alg; visit!( (string) => 0, (int) => 0)(alg); } Error: pure function test cannot call impure function test.visit!(VariantN!(16LU, int, string)).visit ``` std.variant.Algebraic is essentially a std.variant.Variant in different clothes. Variant is very flexible, and this comes at a cost (and isn't used in Algebraic, meaning you pay for things you don't use). Like Dukc said, you might be better off with Taggedalgebraic or SumType (https://code.dlang.org/packages/sumtype). Variant uses runtime type information to hold *any* type. Since Algebraic specifically only holds a few types, all the framework that's in place for Variant is wasted on Algebraic, and makes it less useful and less performant. -- Simen Thank you Simon and Dukc, I've find this: https://issues.dlang.org/show_bug.cgi?id=16662 So, it seems that Phobos isn't in a good shape ... what a pity!
Re: variant visit not pure?
On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote: Good morning, Is there a reason why std.variant.visit is not inferring pure? ``` void test() pure { Algebraic!(int, string) alg; visit!( (string) => 0, (int) => 0)(alg); } Error: pure function test cannot call impure function test.visit!(VariantN!(16LU, int, string)).visit ``` std.variant.Algebraic is essentially a std.variant.Variant in different clothes. Variant is very flexible, and this comes at a cost (and isn't used in Algebraic, meaning you pay for things you don't use). Like Dukc said, you might be better off with Taggedalgebraic or SumType (https://code.dlang.org/packages/sumtype). Variant uses runtime type information to hold *any* type. Since Algebraic specifically only holds a few types, all the framework that's in place for Variant is wasted on Algebraic, and makes it less useful and less performant. -- Simen
Re: variant visit not pure?
On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote: Good morning, Is there a reason why std.variant.visit is not inferring pure? I think `variant` will not infer any trributes. I'm not sure why. It could be some language limitation (that's the reason why `std.range.enumerate` does not infer attributes for example). Or it could be just badly implemented. Either way, there are DUB packages that are better in this (and other) regards. I recommend Taggedalgebraic[1]. [1] https://code.dlang.org/packages/taggedalgebraic
variant visit not pure?
Good morning, Is there a reason why std.variant.visit is not inferring pure? ``` void test() pure { Algebraic!(int, string) alg; visit!( (string) => 0, (int) => 0)(alg); } Error: pure function test cannot call impure function test.visit!(VariantN!(16LU, int, string)).visit ``` Thank you
Re: Map, filter and pure functions
On Friday, 29 November 2019 at 15:54:13 UTC, realhet wrote: On Friday, 29 November 2019 at 15:49:24 UTC, Paul Backus wrote: It's actually a much simpler reason: filter calls .front twice for each element in its input (once to check if the value satisfies the predicate, and then again to return the value if it does), and the range returned by map doesn't save the value of .front between calls, so it has to re-compute it each time by calling the transform function. This makes it clear. In my case a cache which can access all the previous elements would be a too big thing, so I will do the filtering in a later stage manually. But most importantly, now I know what's going on, Thank You! The "cache" wrapper only caches one element at a time. The cached value is discarded after each call to .popFront.
Re: Map, filter and pure functions
On Friday, 29 November 2019 at 15:49:24 UTC, Paul Backus wrote: It's actually a much simpler reason: filter calls .front twice for each element in its input (once to check if the value satisfies the predicate, and then again to return the value if it does), and the range returned by map doesn't save the value of .front between calls, so it has to re-compute it each time by calling the transform function. This makes it clear. In my case a cache which can access all the previous elements would be a too big thing, so I will do the filtering in a later stage manually. But most importantly, now I know what's going on, Thank You!
Re: Map, filter and pure functions
On Friday, 29 November 2019 at 15:30:22 UTC, realhet wrote: ... Unfortunately function purity is not the answer. I put a very long calculation into the transform function which is called from "map!". And the "filter!" is making the "map!" call my function 2 times: First for the "filter!" to decide it allows the element or not. And second when the map! is passing it to the foreach() where I write the elements out. Is there a solution for this performance issue? Using functional programming, my program looks beautiful. But I need it to be optimal too. //To be easier to understand, I want to make the following: foreach(a; input){ auto temp = slowFunction(a); if(check(temp)) writeln(temp); } //But the elegant functional form -> input.map!slowFunction.filter!(a => check(a)).each!writeln; //Produces the following unoptimal solution: foreach(a; input){ if(check(slowFunction(a))) writeln(slowFunction(a)); } Is there a functional way to fix this? Thank you in advance!
Re: Map, filter and pure functions
On Friday, 29 November 2019 at 15:30:22 UTC, realhet wrote: Hi, I have an input range. I use the map! on it to transform using a function. Finally I use filter! on the transformed data. When I do a foreach on this, i noticed, that the transform function is called twice for each element. If I remove the filter! it does only one transform function call per element. Is this because the function is NOT PURE, so Phobos thinks that the function can give different results for the same input? If I modify the function to be pure, will the transform function be called only once? It's actually a much simpler reason: filter calls .front twice for each element in its input (once to check if the value satisfies the predicate, and then again to return the value if it does), and the range returned by map doesn't save the value of .front between calls, so it has to re-compute it each time by calling the transform function. You can work around this using std.algorithm.iteration.cache, a range wrapper that calls .front on the underlying range exactly once, and then saves the value and reuses it for subsequent calls: myRange .map!transform .cache .filter!pred .each!doSomething;
Map, filter and pure functions
Hi, I have an input range. I use the map! on it to transform using a function. Finally I use filter! on the transformed data. When I do a foreach on this, i noticed, that the transform function is called twice for each element. If I remove the filter! it does only one transform function call per element. Is this because the function is NOT PURE, so Phobos thinks that the function can give different results for the same input? If I modify the function to be pure, will the transform function be called only once?
Why is this pure function taking a string literal not CTFE-executable?
Hi Guys! In my programm, I have a custom String-type that I want to initialize some variables of at compile time by casting a string literal to said custom String type. I thought I could achieve this straight forwardly, but after trying a bit, I could not find a (simple) working solution. I made this minimal example to show where the easy solution all fall flat: struct My_String{ long size; char* data; } My_String make_my_string(string s){ My_String my_string; my_string.data = cast(char*) s.ptr; my_string.size = s.length; return my_string; } struct Dummy{ My_String s = make_my_string("hello!"); } void main(){ Dummy dummy; } Which produces the compilation error "cannot use non-constant CTFE pointer in an initializer My_String(6L, &"hello!"[0])". I do not understand this error message. What is the non-constant CTFE pointer here. The "data"-member? If so, why does this compile: struct My_String{ long size; char* data; } struct Dummy{ My_String s = My_String("hello!".length, cast(char*) "hello!".ptr); } void main(){ Dummy dummy; } Why does the error message show an opcall to My_String with filled out members ("6L, &"hello!"[0]"), although the code only ever default-constructs a My_string variable? I am confused. And why on earth does this work: struct My_String{ long size; char* data; } My_String make_my_string(string s){ My_String my_string; my_string.data = cast(char*) s.ptr; my_string.size = s.length; return my_string; } void main(){ My_String s = make_my_string("hello!"); } Please help, I have no idea whats going on here.
Re: Why is my @pure function @system when placed in a struct?
On 27.02.19 19:10, Dukc wrote: I tested a bit, and it appears that attribute inference is not done at all for templates inside structs -the attribute need not be a delegate: struct S { static int fImpl(Ret)() { return Ret.init; } pragma(msg, __traits(getFunctionAttributes, fImpl!int)); // still tells us: `f` is @system } void main(){} A bug, unless I'm overlooking something. It's not quite as simple as that. When you put the pragma in a function, the inferred attributes show up: struct S { void f()() {} } pragma(msg, __traits(getFunctionAttributes, S.f!())); /* @system */ void g() { pragma(msg, __traits(getFunctionAttributes, S.f!())); /* Same line now says @safe. */ } But I agree that this can't be right.
Re: Why is my @pure function @system when placed in a struct?
On Wednesday, 27 February 2019 at 17:23:21 UTC, Q. Schroll wrote: For whatever reason, when I put the code in a struct, the @safe testing line tells me, it's @system now. I tested a bit, and it appears that attribute inference is not done at all for templates inside structs -the attribute need not be a delegate: struct S { static int fImpl(Ret)() { return Ret.init; } pragma(msg, __traits(getFunctionAttributes, fImpl!int)); // still tells us: `f` is @system } void main(){} A bug, unless I'm overlooking something.
Re: Why is my @pure function @system when placed in a struct?
On Wednesday, 27 February 2019 at 18:06:49 UTC, Stefan Koch wrote: the struct gets drawn into your delegate-context. and I guess that taints the function. Even if it did, it should not make the delegate @system. And it does not, since this manifest with static functions and function pointers too.
Re: Why is my @pure function @system when placed in a struct?
On Wednesday, 27 February 2019 at 17:23:21 UTC, Q. Schroll wrote: I have a template function `fImpl` I whish to instantiate manually using the new name `f`. Reason is simple: `f` should not be a template, but overloading it makes it easier that way. Nothing's more simple in D: [...] the struct gets drawn into your delegate-context. and I guess that taints the function.
Why is my @pure function @system when placed in a struct?
I have a template function `fImpl` I whish to instantiate manually using the new name `f`. Reason is simple: `f` should not be a template, but overloading it makes it easier that way. Nothing's more simple in D: int fImpl(T)(T value) { return cast(int) value; } alias f = fImpl!int; alias f = fImpl!long; It works perfectly used like that. In my case, `T` isn't just a simple type, it's a delegate type. So it's rather like this: alias BaseDG = int delegate(ref int); int fImpl(DG : BaseDG)(scope DG callback) { // NB: this is @safe iff callback is @safe int x = 0; return callback(x); } alias myDG = int delegate(ref int) @safe; alias f = fImpl!myDG; When I ask the compiler, if `f` is @safe, it tells me: Hurray, it is! pragma(msg, __traits(getFunctionAttributes, f)); // tells me: `f` is @safe For whatever reason, when I put the code in a struct, the @safe testing line tells me, it's @system now. struct S { // static: // static or not does not matter alias BaseDG = int delegate(ref int); int fImpl(DG : BaseDG)(scope DG callback) { return 0; } alias myDG = int delegate(ref int) @system; alias f = fImpl!myDG; pragma(msg, __traits(getFunctionAttributes, f)); // tells me: `f` is @system } I have no idea why. It is irrelevant if the function template is `static` or even does not call the callback.
Re: Pure opEquals in a class
On Monday, 20 August 2018 at 19:36:15 UTC, werter wrote: The code below doesn't work. Is it possible to make a pure opEquals in a class? [...] pure bool opEquals(const A rhs) const { return b == rhs.b; } It doesn't work because `rhs` has the wrong type. It must be `Object`. override pure bool opEquals(const Object rhs) const { const A a = cast(A) rhs; return b == a.b; }
Pure opEquals in a class
The code below doesn't work. Is it possible to make a pure opEquals in a class? void main() { class A { bool a; int b; this(bool g, int h) { a = g; b = h; } pure bool opEquals(const A rhs) const { return b == rhs.b; } } A a = new A(true, 5); A b = new A(false, 5); assert(a == b); //fails }
Re: float/double to string (pure nothrow @nogc)
On Wednesday, 8 August 2018 at 17:08:57 UTC, vit wrote: Hello, is in phobos some function which convert float/double to string and is pure @nogc and nothrow? Short answer: no. Long answer: https://issues.dlang.org/show_bug.cgi?id=17628
Re: float/double to string (pure nothrow @nogc)
vit wrote: thanks, that code can be modified to pure nothrow @nogc @safe. Is that lib ok? Is little complicated... converting float to string is a *very* complicated task. that lib is quite small for what it is doing ('cause it hacks around some... interesting cases). the *real* thing will be a LOT bigger.
Re: float/double to string (pure nothrow @nogc)
On Wednesday, 8 August 2018 at 17:40:11 UTC, ketmar wrote: vit wrote: Hello, is in phobos some function which convert float/double to string and is pure @nogc and nothrow? i don't think that you can make it `pure`, but you certainly can make it `nothrow`, `@nogc` and ctfe-able. it's dangerous to go alone! take this[0]. [0] http://repo.or.cz/iv.d.git/blob_plain/HEAD:/ctfefloat.d thanks, that code can be modified to pure nothrow @nogc @safe. Is that lib ok? Is little complicated...
Re: float/double to string (pure nothrow @nogc)
vit wrote: Hello, is in phobos some function which convert float/double to string and is pure @nogc and nothrow? i don't think that you can make it `pure`, but you certainly can make it `nothrow`, `@nogc` and ctfe-able. it's dangerous to go alone! take this[0]. [0] http://repo.or.cz/iv.d.git/blob_plain/HEAD:/ctfefloat.d
Re: float/double to string (pure nothrow @nogc)
On 8/8/18 1:08 PM, vit wrote: Hello, is in phobos some function which convert float/double to string and is pure @nogc and nothrow? Not one that I can see. formattedWrite doesn't seem to be pure. -Steve
float/double to string (pure nothrow @nogc)
Hello, is in phobos some function which convert float/double to string and is pure @nogc and nothrow?
Re: Implicit conversion of struct with methods to immutable in pure function fails
On Thursday, 19 July 2018 at 06:35:36 UTC, Simen Kjærås wrote: On Wednesday, 18 July 2018 at 11:28:54 UTC, Timoses wrote: But why is a context pointer a problem? Is it problematic because the context pointer to the main scope can not guarantee `immutable`? E.g. if I happened to use data from main in a function of the immutable struct then... well then what? The struct would still be immutable, but what would prevent a function from using non-immutable data? It's a known bug: https://issues.dlang.org/show_bug.cgi?id=18563 In the associated discussion (https://forum.dlang.org/thread/p7lp2b$1jod$1...@digitalmars.com), Steven Schveighoffer points out that an immutable struct may be passed to other threads, which would give one thread access to another thread's stack. This could be a good enough reason to prevent this kind of conversion, but a better error message would still make sense. -- Simen Thanks so much for the pointer, Simen. Interesting discussion.
Re: Implicit conversion of struct with methods to immutable in pure function fails
On Wednesday, 18 July 2018 at 11:28:54 UTC, Timoses wrote: But why is a context pointer a problem? Is it problematic because the context pointer to the main scope can not guarantee `immutable`? E.g. if I happened to use data from main in a function of the immutable struct then... well then what? The struct would still be immutable, but what would prevent a function from using non-immutable data? It's a known bug: https://issues.dlang.org/show_bug.cgi?id=18563 In the associated discussion (https://forum.dlang.org/thread/p7lp2b$1jod$1...@digitalmars.com), Steven Schveighoffer points out that an immutable struct may be passed to other threads, which would give one thread access to another thread's stack. This could be a good enough reason to prevent this kind of conversion, but a better error message would still make sense. -- Simen
Re: Implicit conversion of struct with methods to immutable in pure function fails
On Tuesday, 17 July 2018 at 06:24:12 UTC, Simen Kjærås wrote: That makes sense. The problem is F has a context pointer to the main() block, since it's a non-static struct with methods inside a block. It doesn't actually use the context pointer for anything, so it possibly shouldn't have one, but it does, so we have to work around it. The fix is to mark F as static, or move it outside the main() block. -- Simen Thanks for the explanation. But why is a context pointer a problem? Is it problematic because the context pointer to the main scope can not guarantee `immutable`? E.g. if I happened to use data from main in a function of the immutable struct then... well then what? The struct would still be immutable, but what would prevent a function from using non-immutable data? E.g. I could do this int gnumber = 3; struct F { int i; void fun() immutable { gnumber = 5; } } void main () { immutable F f = F(); f.fun; } I declared `fun()` to be an immutable function. So calling the immutable struct function `F.fun()` changes a module scope int. The same could be applied to local data of the main scope, however the following fails: void main () { int mnumber = 3; struct F { int i; void fun() immutable { // Error: immutable function onlineapp.main.F.fun cannot access mutable data mnumber mnumber = 5; } } immutable F f = F(); f.fun; } Is this connected why I can't implicitly convert a local struct with a context pointer to immutable? What's the reason behind it?
Re: Implicit conversion of struct with methods to immutable in pure function fails
On Monday, 16 July 2018 at 13:13:53 UTC, Timoses wrote: On Monday, 16 July 2018 at 12:00:57 UTC, Simen Kjærås wrote: On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote: Why does this fail? It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen https://run.dlang.io/is/Pgs527 I'm on 2.080.1. But above is on latest 2.081.1 I believe. Note that the bottom code snippet in the original post does work, while the first one does not. That makes sense. The problem is F has a context pointer to the main() block, since it's a non-static struct with methods inside a block. It doesn't actually use the context pointer for anything, so it possibly shouldn't have one, but it does, so we have to work around it. The fix is to mark F as static, or move it outside the main() block. -- Simen
Re: Implicit conversion of struct with methods to immutable in pure function fails
On Monday, 16 July 2018 at 13:13:53 UTC, Timoses wrote: On Monday, 16 July 2018 at 12:00:57 UTC, Simen Kjærås wrote: On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote: Why does this fail? It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen https://run.dlang.io/is/Pgs527 I'm on 2.080.1. But above is on latest 2.081.1 I believe. Note that the bottom code snippet in the original post does work, while the first one does not. Yep, run.dlang.io automatically updates itself to the latest compiler (you can check this e.g. with -v).
Re: Implicit conversion of struct with methods to immutable in pure function fails
On Monday, 16 July 2018 at 12:00:57 UTC, Simen Kjærås wrote: On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote: Why does this fail? It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen https://run.dlang.io/is/Pgs527 I'm on 2.080.1. But above is on latest 2.081.1 I believe. Note that the bottom code snippet in the original post does work, while the first one does not.
Re: Implicit conversion of struct with methods to immutable in pure function fails
On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote: Why does this fail? It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen
Implicit conversion of struct with methods to immutable in pure function fails
Why does this fail? struct F { int i; ushort _x; void x(ushort v) pure {_x = v;} ushort x() const { return _x; } } immutable F f1 = () pure { F lf = F(); return lf; }(); // Error: cannot implicitly convert expression delegate () => lf() of type F to immutable(F) F makeF() pure { F lf = F(); return lf; } immutable F f2 = makeF(); // Error: cannot implicitly convert expression makeF() of type F to immutable(F) Removing the methods in struct F compiles fine. Background: I have a mixin(bitfields!(...)) in the struct which utilizes member functions. / Idea: Just found out that it works when making the struct static. But why does that help? Is it because the compiler wouldn't be able to check whether methods in the struct are accessing non-immutable data in the enclosing context? That would not make much sense though because the following works: // Compiles fine! int modi = 3; void main () { static struct F { int var() immutable { return modi; } // accessing modi from module scope } immutable f = () pure { F f = F(); return f; }(); } So my explanation wouldn't make sense, since why would it be okay to use module-scope data and not enclosing context data? So where does that limitation come from that I implicitly convert a nested struct to immutable in a pure function?
Re: immutable / inout / pure headaches
On Friday, 6 July 2018 at 15:44:28 UTC, Steven Schveighoffer wrote: I'm long overdue for an inout article... I can point you at my talk from 2016: https://www.youtube.com/watch?v=UTz55Lv9FwQ Thanks, will definitely take a look when I get home. I never really used 'pure' and just now found a use case with immutable [1], i.e. to return unique objects from functions which can be assigned to a mutable or immutable reference. What other "use cases" or reasons to use 'pure' are there (aside from compiler optimizations)? The reason pure functions allow mutability changes is due to the nature of what pure means semantically -- you have guarantees that nothing else goes in or out, so it's possible to deduce what is unique and what is not. This is powerful to a human reader of a function as well! Without seeing the insides, it tells you exactly what it can and cannot affect, giving you more understanding of when it can be used and when it can't. It helps write safer more tractable code, IMO. In the end, all these attributes are to help reason about large code bases without having to read ALL the code. Sounds like a good idea to always use it whenever possible. For me as a kind of novice it takes time to understand the purpose and meaning of each of those attributes. I guess I got one step closer to understanding "Why pure?". That leaves @nogc, @safe and @trusted :D. I feel the best way to understand these idioms is to experience the "trouble" oneself. I knew in some way what pure functions were from the spec, but I didn't have an example at hand that made "non-usage" of pure painful.
Re: immutable / inout / pure headaches
On 7/6/18 11:22 AM, Timoses wrote: On Friday, 6 July 2018 at 14:28:39 UTC, Steven Schveighoffer wrote: inout is not a compile-time wildcard, it's a runtime one. So it doesn't know how to convert an immutable to an inout. Essentially, inside this function, the compiler has no idea whether the real thing is an immutable, const, mutable, etc. The fix is simple, replace both your constructors with one inout constructor: this(inout(S) t) inout { this.s = t; } Slowly getting acquainted to inout... Feels like magic. I'm long overdue for an inout article... I can point you at my talk from 2016: https://www.youtube.com/watch?v=UTz55Lv9FwQ "viral" is very fitting. Throw in pure and I quickly reach the bottom of my program hitting a library function I used which is not pure. I never really used 'pure' and just now found a use case with immutable [1], i.e. to return unique objects from functions which can be assigned to a mutable or immutable reference. What other "use cases" or reasons to use 'pure' are there (aside from compiler optimizations)? The reason pure functions allow mutability changes is due to the nature of what pure means semantically -- you have guarantees that nothing else goes in or out, so it's possible to deduce what is unique and what is not. This is powerful to a human reader of a function as well! Without seeing the insides, it tells you exactly what it can and cannot affect, giving you more understanding of when it can be used and when it can't. It helps write safer more tractable code, IMO. In the end, all these attributes are to help reason about large code bases without having to read ALL the code. -Steve
Re: immutable / inout / pure headaches
On Friday, 6 July 2018 at 14:28:39 UTC, Steven Schveighoffer wrote: inout is not a compile-time wildcard, it's a runtime one. So it doesn't know how to convert an immutable to an inout. Essentially, inside this function, the compiler has no idea whether the real thing is an immutable, const, mutable, etc. The fix is simple, replace both your constructors with one inout constructor: this(inout(S) t) inout { this.s = t; } Slowly getting acquainted to inout... Feels like magic. And it will work for everything. One word of caution though -- inout is viral (just like immutable). Everything you use has to support it, or it breaks down. "viral" is very fitting. Throw in pure and I quickly reach the bottom of my program hitting a library function I used which is not pure. I never really used 'pure' and just now found a use case with immutable [1], i.e. to return unique objects from functions which can be assigned to a mutable or immutable reference. What other "use cases" or reasons to use 'pure' are there (aside from compiler optimizations)? [1]: https://forum.dlang.org/post/nmcnuenazaghjlxod...@forum.dlang.org
Re: immutable / inout / pure headaches
On 7/6/18 7:10 AM, Timoses wrote: I dared once again getting into immutable by adding an "immutable" keyword which causes a chain of actions to be taken. I feel like I'm lost in a jungle of immutable, inout and pure (perhaps more will join the party...). To start off, why does this not work? class Test { private S s; this(S t) { this.s = t; } this(immutable S t) immutable { this.s = t; } inout(Test) get() inout { // Error: none of the overloads of __ctor are callable using a inout object, candidates are: //onlineapp.d(10): onlineapp.Test.this(S t) //onlineapp.d(11): onlineapp.Test.this(immutable(S) t) return new inout Test(this.s); } inout is not a compile-time wildcard, it's a runtime one. So it doesn't know how to convert an immutable to an inout. Essentially, inside this function, the compiler has no idea whether the real thing is an immutable, const, mutable, etc. The fix is simple, replace both your constructors with one inout constructor: this(inout(S) t) inout { this.s = t; } And it will work for everything. One word of caution though -- inout is viral (just like immutable). Everything you use has to support it, or it breaks down. -Steve
Re: immutable / inout / pure headaches
On Friday, July 06, 2018 11:10:27 Timoses via Digitalmars-d-learn wrote: > I dared once again getting into immutable by adding an > "immutable" keyword which causes a chain of actions to be taken. > I feel like I'm lost in a jungle of immutable, inout and pure > (perhaps more will join the party...). > > To start off, why does this not work? > > > class Test > { > private S s; > this(S t) { this.s = t; } > this(immutable S t) immutable { this.s = t; } > > inout(Test) get() inout > { > // Error: none of the overloads of __ctor are > callable using a inout object, candidates are: > //onlineapp.d(10):onlineapp.Test.this(S t) > //onlineapp.d(11):onlineapp.Test.this(immutable(S) t) > return new inout Test(this.s); > } > } > > struct S > { > int[] a; > } > void main() > { > immutable S s = immutable S([1,2,3]); > auto t = new immutable Test(s); > } You have no constructor that will work with inout - only mutable amd immutable. inout is only going to work when the object is always treated as either inout or const, because it could be an object that's mutable, const, or immutable. It can't ever treat it as mutable or immutable within the function that marks it as inout. - Jonathan M Davis
immutable / inout / pure headaches
I dared once again getting into immutable by adding an "immutable" keyword which causes a chain of actions to be taken. I feel like I'm lost in a jungle of immutable, inout and pure (perhaps more will join the party...). To start off, why does this not work? class Test { private S s; this(S t) { this.s = t; } this(immutable S t) immutable { this.s = t; } inout(Test) get() inout { // Error: none of the overloads of __ctor are callable using a inout object, candidates are: //onlineapp.d(10):onlineapp.Test.this(S t) //onlineapp.d(11):onlineapp.Test.this(immutable(S) t) return new inout Test(this.s); } } struct S { int[] a; } void main() { immutable S s = immutable S([1,2,3]); auto t = new immutable Test(s); }