Re: dlang.org/spec/function.html#pure-functions example

2023-10-28 Thread Nick Treleaven via Digitalmars-d-learn

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

2023-10-21 Thread Jonathan M Davis via Digitalmars-d-learn
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

2023-10-21 Thread Jonathan M Davis via Digitalmars-d-learn
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

2023-10-16 Thread Paul via Digitalmars-d-learn
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

2023-10-16 Thread Paul via Digitalmars-d-learn
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

2023-10-13 Thread Nick Treleaven via Digitalmars-d-learn

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

2023-10-12 Thread Jonathan M Davis via Digitalmars-d-learn
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`

2023-08-02 Thread Jonathan M Davis via Digitalmars-d-learn
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`

2023-08-02 Thread Nick Treleaven via Digitalmars-d-learn

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`

2023-08-02 Thread Nick Treleaven via Digitalmars-d-learn

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.

2022-12-27 Thread Stefan Koch via Digitalmars-d-learn

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.

2022-12-27 Thread Johan via Digitalmars-d-learn
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.

2022-12-27 Thread Richard (Rikki) Andrew Cattermole via Digitalmars-d-learn

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.

2022-12-27 Thread Alexandru Ermicioi via Digitalmars-d-learn
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.

2022-12-26 Thread Richard (Rikki) Andrew Cattermole via Digitalmars-d-learn

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.

2022-12-26 Thread Alexandru Ermicioi via Digitalmars-d-learn

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?

2022-10-29 Thread max haughton via Digitalmars-d-learn

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?

2022-10-28 Thread Siarhei Siamashka via Digitalmars-d-learn

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?

2022-10-28 Thread Imperatorn via Digitalmars-d-learn

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?

2022-10-28 Thread ab via Digitalmars-d-learn

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?

2022-10-27 Thread Dennis via Digitalmars-d-learn

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?

2022-10-27 Thread H. S. Teoh via Digitalmars-d-learn
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?

2022-10-27 Thread Imperatorn via Digitalmars-d-learn

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?

2022-10-27 Thread ab via Digitalmars-d-learn

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?

2021-11-25 Thread Paul Backus via Digitalmars-d-learn

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?

2021-11-25 Thread zjh via Digitalmars-d-learn

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?

2021-11-25 Thread Imperatorn via Digitalmars-d-learn

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?

2021-11-24 Thread sclytrack via Digitalmars-d-learn
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

2021-08-02 Thread Tejas via Digitalmars-d-learn

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

2021-08-02 Thread vit via Digitalmars-d-learn

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

2021-08-02 Thread vit via Digitalmars-d-learn

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

2021-08-02 Thread Tejas via Digitalmars-d-learn

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

2021-06-14 Thread baby_tiger via Digitalmars-d-learn
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

2021-02-12 Thread Petar via Digitalmars-d-learn

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

2021-02-12 Thread Petar via Digitalmars-d-learn

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

2021-02-12 Thread vitamin via Digitalmars-d-learn
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

2021-02-12 Thread Per Nordlöw via Digitalmars-d-learn

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

2021-02-10 Thread Petar via Digitalmars-d-learn
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

2021-02-10 Thread Petar via Digitalmars-d-learn

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

2021-02-10 Thread vit via Digitalmars-d-learn

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

2021-02-10 Thread rm via Digitalmars-d-learn

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

2021-02-10 Thread Dominikus Dittes Scherkl via Digitalmars-d-learn

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

2021-02-09 Thread Paul Backus via Digitalmars-d-learn

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

2021-02-09 Thread Max Haughton via Digitalmars-d-learn

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

2021-02-09 Thread Temtaime via Digitalmars-d-learn

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

2021-02-08 Thread frame via Digitalmars-d-learn

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

2021-02-07 Thread vitamin via Digitalmars-d-learn
Why using 'new' is allowed in pure functions but calling 
GC.addRange or GC.removeRange isn't allowed?


Re: Escape this in pure members

2020-09-23 Thread ag0aep6g via Digitalmars-d-learn

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

2020-09-23 Thread Per Nordlöw via Digitalmars-d-learn
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

2020-09-22 Thread DlangUser38 via Digitalmars-d-learn
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

2020-09-22 Thread Jacob Carlborg via Digitalmars-d-learn

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

2020-09-19 Thread Per Nordlöw via Digitalmars-d-learn
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

2020-09-19 Thread Jacob Carlborg via Digitalmars-d-learn

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

2020-09-19 Thread Per Nordlöw via Digitalmars-d-learn

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

2020-09-19 Thread Per Nordlöw via Digitalmars-d-learn
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?

2020-05-08 Thread Dukc via Digitalmars-d-learn

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?

2020-05-08 Thread Dukc via Digitalmars-d-learn

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?

2020-05-08 Thread Dukc via Digitalmars-d-learn

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?

2020-05-07 Thread learner via Digitalmars-d-learn
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?

2020-05-07 Thread Paul Backus via Digitalmars-d-learn

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?

2020-05-07 Thread Ben Jones via Digitalmars-d-learn
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?

2020-05-07 Thread Steven Schveighoffer via Digitalmars-d-learn

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?

2020-05-07 Thread Dukc via Digitalmars-d-learn

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?

2020-05-07 Thread learner via Digitalmars-d-learn

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?

2020-05-07 Thread Simen Kjærås via Digitalmars-d-learn

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?

2020-05-07 Thread Dukc via Digitalmars-d-learn

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?

2020-05-07 Thread learner via Digitalmars-d-learn

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

2019-11-29 Thread Paul Backus via Digitalmars-d-learn

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

2019-11-29 Thread realhet via Digitalmars-d-learn

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

2019-11-29 Thread realhet via Digitalmars-d-learn

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

2019-11-29 Thread Paul Backus via Digitalmars-d-learn

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

2019-11-29 Thread realhet via Digitalmars-d-learn

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?

2019-06-01 Thread Simon via Digitalmars-d-learn

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?

2019-02-27 Thread ag0aep6g via Digitalmars-d-learn

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?

2019-02-27 Thread Dukc via Digitalmars-d-learn

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?

2019-02-27 Thread Dukc via Digitalmars-d-learn

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?

2019-02-27 Thread Stefan Koch via Digitalmars-d-learn

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?

2019-02-27 Thread Q. Schroll via Digitalmars-d-learn
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

2018-08-20 Thread ag0aep6g via Digitalmars-d-learn

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

2018-08-20 Thread werter via Digitalmars-d-learn
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)

2018-08-08 Thread Paul Backus via Digitalmars-d-learn

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)

2018-08-08 Thread ketmar via Digitalmars-d-learn

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)

2018-08-08 Thread vit via Digitalmars-d-learn

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)

2018-08-08 Thread ketmar via Digitalmars-d-learn

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)

2018-08-08 Thread Steven Schveighoffer via Digitalmars-d-learn

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)

2018-08-08 Thread vit via Digitalmars-d-learn
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

2018-07-19 Thread Timoses via Digitalmars-d-learn

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

2018-07-19 Thread Simen Kjærås via Digitalmars-d-learn

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

2018-07-18 Thread Timoses via Digitalmars-d-learn

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

2018-07-17 Thread Simen Kjærås via Digitalmars-d-learn

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

2018-07-16 Thread Seb via Digitalmars-d-learn

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

2018-07-16 Thread Timoses via Digitalmars-d-learn

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

2018-07-16 Thread Simen Kjærås via Digitalmars-d-learn

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

2018-07-16 Thread Timoses via Digitalmars-d-learn

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

2018-07-06 Thread Timoses via Digitalmars-d-learn
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

2018-07-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2018-07-06 Thread Timoses via Digitalmars-d-learn
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

2018-07-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2018-07-06 Thread Jonathan M Davis via Digitalmars-d-learn
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

2018-07-06 Thread Timoses via Digitalmars-d-learn
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);
}



  1   2   3   4   5   6   >