Re: Mallocator and 'shared'
On Sunday, 12 February 2017 at 20:08:05 UTC, bitwise wrote: Given that both the data and the method are 'shared', a caller should know that race conditions are possible and that they should aquire a lock before accessing either of them...or so it would seem. Thread unsafe methods shouldn't be marked shared, it doesn't make sense. If you don't want to provide thread-safe interface, don't mark methods as shared, so they will not be callable on a shared instance and thus the user will be unable to use the shared object instance and hence will know the object is thread unsafe and needs manual synchronization. ps Memory barriers are a bad idea because they don't defend from a race condition, but they look like they do :) use std.concurrency for a simple and safe concurrency, that's what it's made for.
Alias type with different initialiser.
Hi, In Extended Pascal, you can derive from a basic type and change the default initialiser like so: type int1 = integer value 1; var i : int1; ii : int1 value 2; assert(i = 1); assert(ii = 2); I have it working in D, but it seems a little clumsy. Is there a better way? struct initial(T, T val) { private T _payload = val; alias _payload this; static initial opCall(T v) { initial s; s._payload = v; return s; } } unittest { alias initial!(int, 1) int1; int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); }
Re: Alias type with different initialiser.
Dne 13.2.2017 v 16:28 Bastiaan Veelo via Digitalmars-d-learn napsal(a): Hi, In Extended Pascal, you can derive from a basic type and change the default initialiser like so: type int1 = integer value 1; var i : int1; ii : int1 value 2; assert(i = 1); assert(ii = 2); I have it working in D, but it seems a little clumsy. Is there a better way? struct initial(T, T val) { private T _payload = val; alias _payload this; static initial opCall(T v) { initial s; s._payload = v; return s; } } unittest { alias initial!(int, 1) int1; int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); } https://dlang.org/phobos/std_typecons.html#.Typedef
Re: Alias type with different initialiser.
Dne 13.2.2017 v 17:40 Daniel Kozak napsal(a): Dne 13.2.2017 v 16:28 Bastiaan Veelo via Digitalmars-d-learn napsal(a): Hi, In Extended Pascal, you can derive from a basic type and change the default initialiser like so: type int1 = integer value 1; var i : int1; ii : int1 value 2; assert(i = 1); assert(ii = 2); I have it working in D, but it seems a little clumsy. Is there a better way? struct initial(T, T val) { private T _payload = val; alias _payload this; static initial opCall(T v) { initial s; s._payload = v; return s; } } unittest { alias initial!(int, 1) int1; int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); } https://dlang.org/phobos/std_typecons.html#.Typedef or you can use Proxy https://dlang.org/phobos/std_typecons.html#.Proxy struct initial(T, T val) { private T _payload = val; mixin Proxy!_payload; this(T v) { _payload = v; } } unittest { alias initial!(int, 1) int1; int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); }
Re: Mallocator and 'shared'
On Monday, 13 February 2017 at 14:20:05 UTC, Kagamin wrote: Thread unsafe methods shouldn't be marked shared, it doesn't make sense. If you don't want to provide thread-safe interface, don't mark methods as shared, so they will not be callable on a shared instance and thus the user will be unable to use the shared object instance and hence will know the object is thread unsafe and needs manual synchronization. To be clear: While I might, in general, agree that using shared methods only for thread safe methods seems to be a sensible restriction, neither language nor compiler require it to be so; and absence of evidence of a useful application is not evidence of absence. On Monday, 13 February 2017 at 14:20:05 UTC, Kagamin wrote: ps Memory barriers are a bad idea because they don't defend from a race condition, but they look like they do :) There are two very common pitfalls in non-sequential programming with regards to reads/writes to memory shared between threads: Issue 1: Sequencing/Interleaving of several threads into the logical memory access order Issue 2: Reordering of code within one thread Code that changes semantics because of issue 1 has race conditions; fixing it requires synchronization primitives, such as locking opcode, transactional memory, etc. Code that changes semantics because of issue 2 may or may not have race conditions, but it definitely requires memory barriers. Claiming that memory barriers are a bad idea because they don't defend against race conditions, but look like they do (when that's what synchronization is for) is similar enough to saying airbags in cars are a bad idea because they don't keep your body in place, but look like they do (when that's what seat belts are for). My point here being that I don't understand what made you state that memory barriers look like they deal with race conditions, as they have nothing to do with that. To be clear: Synchronization (the fix for race conditions) does not help you to deal with issue 2. If my last example had instead been --- __gshared int f = 0, x = 0; Object monitor; // thread 1 synchronized (monitor) while (f == 0); // Memory barrier required here synchronized (monitor) writeln(x) // thread 2 synchronized (monitor) x = 42; // Memory barrier required here synchronized (monitor) f = 1; --- you'd still need those memory barriers. Also note that the synchronization in the above is not needed in terms of semantics. The code has no race conditions, all permutations of the (interleaved) memory access order yield the same output from thread 1. Also, since synchronization primitives and memory barriers have different runtime costs, depending on your hardware support and how they are translated to that support from D, there's no "one size fits all" solution on the low level we're on here. My opinion on the matter of `shared` emitting memory barriers is that either the spec and documentation[1] should be updated to reflect that sequential consistency is a non-goal of `shared` (and if that is decided this should be accompanied by an example of how to add memory barriers yourself), or it should be implemented. Though leaving it in the current "not implemented, no comment / plan on whether/when it will be implemented" state seems to have little practical consequence - since no one seems to actually work on this level in D - and I can thus understand why dealing with that is just not a priority. On Monday, 13 February 2017 at 14:20:05 UTC, Kagamin wrote: use std.concurrency for a simple and safe concurrency, that's what it's made for. I agree, message passing is considerably less tricky and you're unlikely to shoot yourself in the foot. Nonetheless, there are valid use cases where the overhead of MP may not be acceptable. [1] https://dlang.org/faq.html#shared_guarantees
Re: Alias type with different initialiser.
On Monday, 13 February 2017 at 16:40:02 UTC, Daniel Kozak wrote: https://dlang.org/phobos/std_typecons.html#.Typedef Thanks for the pointers. Both Typedef and Proxy create types that don't mix with the base type, which I want to the contrary. So I guess I'll go with struct Initial(T, T val) { private T _payload = val; alias _payload this; static Initial opCall(T v) { Initial s; s._payload = v; return s; } static T init() { return val; } } unittest { alias Initial!(int, 1) int1; int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); assert(ii.init == 1); assert(int1.init == 1); void f(int val) { assert(val == 1); } f(i); int i0; assert(i0 == 0); i = i0; assert(i == 0); assert(i.init == 1); i0 = ii; assert(i0 == 2); assert(i0.init == 0); }
Re: Alias type with different initialiser.
On Monday, 13 February 2017 at 22:16:36 UTC, Bastiaan Veelo wrote: On Monday, 13 February 2017 at 16:40:02 UTC, Daniel Kozak wrote: https://dlang.org/phobos/std_typecons.html#.Typedef Thanks for the pointers. Both Typedef and Proxy create types that don't mix with the base type, which I want to the contrary. So I guess I'll go with Why not use a constructor instead of static opCall? Also, it's generally a bad idea to define `.init` for any type as code generally expects this to be the compiler-generated property (e.g. a value of type Initial!(int, 1) not of type int). So, perhaps like this: struct Initial(T, T val) { private T _payload = val; alias _payload this; this(T v) { _payload = v; } enum initial = val; } unittest { alias Initial!(int, 1) int1; static assert(int1.initial == 1); // typeof(int1.initial) == int static assert(int1.init == 1); // typeof(int1.init) == typeof(int1) int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); assert(ii.init == 1); assert(int1.init == 1); void f(int val) { assert(val == 1); } f(i); int i0; assert(i0 == 0); i = i0; assert(i == 0); assert(i.init == 1); i0 = ii; assert(i0 == 2); assert(i0.init == 0); }
Creating an array of immutable objects
Hi, I have a struct with two immutable members, and I want to make an array of them. How do I to this? I'm using allocators for this. string[] paths; struct FileDesc { immutable string path; immutable uint index; } _fileDesc = /*something*/; You can't use alloc.makeArray because it requires a range with which to initialize the array, and while I can produce an array of paths, I don't know how to merge both a range of paths and indices. Lockstep doesn't work. I also tried using emplace and an allocated byte array, but it gave me random values and was (I think) unnecessarily complicated. What am I missing?
Re: Creating an array of immutable objects
On 02/13/2017 04:59 PM, David Zhang wrote: I have a struct with two immutable members, and I want to make an array of them. How do I to this? I'm using allocators for this. I realize that I misunderstood you; see below for a mutable array. The following code produces an immutable array through the use of the misplaced std.exception.assumeUnique. (Why is it in std.exception? :) ) import std.stdio; import std.algorithm; import std.range; string[] paths = [ "hello", "world" ]; struct FileDesc { immutable string path; immutable uint index; } immutable(FileDesc[]) _fileDesc; FileDesc[] makeFileDescs(string[] paths) pure { return paths.enumerate!uint.map!(t => FileDesc(t[1], t[0])).array; } static this() { import std.exception : assumeUnique; auto fd = makeFileDescs(paths); _fileDesc = assumeUnique(fd); } void main() { _fileDesc.each!writeln; } A mutable array is simpler: import std.stdio; import std.algorithm; import std.range; string[] paths = [ "hello", "world" ]; struct FileDesc { immutable string path; immutable uint index; } FileDesc[] _fileDesc; FileDesc[] makeFileDescs(string[] paths) pure { return paths.enumerate!uint.map!(t => FileDesc(t[1], t[0])).array; } static this() { _fileDesc = makeFileDescs(paths); } void main() { _fileDesc.each!writeln; } Ali
Re: Alias type with different initialiser.
On Monday, 13 February 2017 at 22:59:11 UTC, John Colvin wrote: [ snip ] sorry, made a typo, that should have been alias int1 = Initial!(int, 1); static assert(int1.initial == 1); // typeof(int1.initial) == int static assert(int1.init == 1); // typeof(int1.init) == int1
Policy-based design in D
Tonight I stumbled upon Andrei's concept of policy-based design (https://en.wikipedia.org/wiki/Policy-based_design) and tried to implement their example in D with the lack of multiple inheritance in mind. https://dpaste.dzfl.pl/adc05892344f (btw, any reason why certificate validation on dpaste fails right now?) The implementation isn't perfect, as I'm not sure how to check members of mixin templates so that you could verify whether print() and message() are actually where they should be. How would you do that? Is there any use for this kind of thing in D, and if so, what would it be? I've hardly dabbled in OOP patterns, but the abstraction seems kinda interesting.
Re: Policy-based design in D
Dne 14.2.2017 v 07:48 TheGag96 via Digitalmars-d-learn napsal(a): https://dpaste.dzfl.pl/adc05892344f (btw, any reason why certificate validation on dpaste fails right now?) Because certificate is expired, dpaste use certs from Lets Encrypt which has short time of validity I have same issue in the past with my websites, now I am using cron to keep it updated 1 0 * * * certbot renew --nginx --keep-until-expiring