Re: Copying parameter lists verbatim

2014-07-19 Thread Jakob Ovrum via Digitalmars-d
On Saturday, 19 July 2014 at 06:13:10 UTC, Manu via Digitalmars-d 
wrote:

Anyway, does anybody know a nice tidy way to do it?


Unfortunately the only way to create perfect forwarding functions 
completely generically is still using an ugly string mixin that 
generates the forwarding function. A subset of forwarding 
functions can be created using templates and auto-ref, but of 
course a function template has many disadvantages to a concrete 
function (virtual functions being a good example).


Re: Copying parameter lists verbatim

2014-07-20 Thread Jakob Ovrum via Digitalmars-d
On Saturday, 19 July 2014 at 17:40:01 UTC, Andrei Alexandrescu 
wrote:

On 7/19/14, 9:36 AM, Jakob Ovrum wrote:
On Saturday, 19 July 2014 at 06:13:10 UTC, Manu via 
Digitalmars-d wrote:

Anyway, does anybody know a nice tidy way to do it?


Unfortunately the only way to create perfect forwarding 
functions

completely generically is still using an ugly string mixin that
generates the forwarding function. A subset of forwarding 
functions can
be created using templates and auto-ref, but of course a 
function

template has many disadvantages to a concrete function (virtual
functions being a good example).


How can this be encapsulated as a library artifact? -- Andrei


Since the key parts of the forwarding function - the parameter 
list and attribute list - are part of the signature, the entire 
function declaration has to be mixed in. That means the function 
body has to be provided as a string argument. This tends to cause 
some seriously unreadable code. It may be a lost cause but I'm 
hoping we can amend the language to avoid that.


Re: DIP65: Fixing Exception Handling Syntax

2014-07-21 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 17 July 2014 at 21:03:08 UTC, Walter Bright wrote:

Did you see my response?

I suggested recognizing in the parser:

   ( Identifier )

as a special case, in addition to using Parser::isDeclaration().


I just want to point out that this special case is lacking, and 
will inevitably cause someone a headache when they try to do 
something like:


catch(typeof(foo)) {
...
}

Which is currently valid (as I'd expect).


Opportunistic worst-case complexity upgrade? aka binary search with `find`

2014-07-23 Thread Jakob Ovrum via Digitalmars-d
We should talk about a design question surrounding binary search 
with `canFind`/`find` and possibly other linear-search functions.


Currently we have binary search in Phobos as part of 
std.range.SortedRange. Its interface is not compatible with 
`canFind` or `find` - you can't simply wrap the haystack in a 
SortedRange and pass it to an algorithm to give you logarithmic 
complexity.


The first question is whether this opportunistic upgrade is 
desirable - binary search has much better worst-case complexity 
than linear search, but it's not necessarily faster in the 
average case, which depends on the specific use pattern. One 
important thing to note is that, assuming the binary-search 
specialization is documented, the user can use 
`SortedRange.release` to explicitly request linear search.


Myself and others have sometimes mistakenly expected `find` and 
friends to be specialized for `SortedRange` inputs, 
opportunistically providing better worst-case complexity, but 
this is not the case. It seems simple at first glance, but the 
problem lies in the predicate - binary search can only be 
leveraged when the specific order is known:


---
auto data = assumeSorted([1, 2, 3]);

// Equality, so bsearch then trot left
auto result = data.find!((x, e) = x == e)(2); // default 
predicate

assert(result.equal([2, 3]));

// Opposite order and exclusive, bsearch then trot right
result = data.find!((x, e) = x  e)(2);
assert(result.equal([3]));

// Same order, bsearch then trot left.
// Compare first element as an optimization?
result = data.find!((x, e) = x  e)(0);
assert(result.empty);

struct S { string name; }
auto data2 = assumeSorted!((a, b) = a.name  b.name)(
[S(a), S(b), S(c)]
);

// Same order and exclusive, but with a transformation, yikes...
auto result2 = data2.find!((x, e) = x.name  e.name)(S(b));
assert(result2.equal(data2));
---

Identifying the characteristics described in the code comments 
above is the biggest problem: predicate functions don't have any 
notion of equality.


String lambdas can be compared for equality, but they're really 
fragile: a == b != b == a etc. Besides, string lambdas are 
undesirable for other reasons and should be phased out in the 
long-term[1].


Someone suggested defining a standard set of predicates, making 
it look like this:


---
auto data = assumeSorted!less([1, 2, 3]); // Would be default

// Equality, so bsearch then trot left
auto result = data.find!equality(2); // Would be default
---

Templates can be compared with __traits(isSame, ...), so this 
approach seems feasible. If we want to do this, this seems like 
the most realistic approach. I'm not sure if it can be made to 
work when transformation of arguments is involved, but it might 
still be worth doing.


Another issue is that SortedRange's interface does not actually 
support all the above patterns because it splits the result into 
3 instead of 2; we would need to amend SortedRange to support the 
inverse functions of lowerBound and upperBound.


So, what does the community think? Desirable, or not? Thoughts 
about implementation?


[1] 
http://forum.dlang.org/post/jnlqesrwxfekdsxje...@forum.dlang.org


Re: Opportunistic worst-case complexity upgrade? aka binary search with `find`

2014-07-23 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 24 July 2014 at 01:21:44 UTC, Jakob Ovrum wrote:

-snip-


Another point is that the range types of the two currently 
available sorted containers - RedBlackTree and BinaryHeap - are 
*not* instances of SortedRange. If algorithms working on sorted 
ranges become a thing, it seems like they should be.


Re: Template argument deduction and default args

2014-07-24 Thread Jakob Ovrum via Digitalmars-d
On Thursday, 24 July 2014 at 07:01:09 UTC, Manu via Digitalmars-d 
wrote:
I imagine that would be a compile error; the static if can't be 
resolved

without knowing T, and prior to resolution of the static if, no
constructors exist.


Please lay out this kind of logic in a DIP so it can actually be 
implemented. As I said in the enhancement request, the problem is 
defining the feature for the general case; that means defining it 
so the compiler knows how to proceed in all cases (including when 
to error). If we can't define this robustly it will become a pain 
in the ass for both users and compiler-writers.


Re: Review: std.logger

2014-07-24 Thread Jakob Ovrum via Digitalmars-d

On Friday, 11 July 2014 at 14:36:34 UTC, Dicebot wrote:
Round of a formal review before proceeding to voting. Subject 
for Phobos inclusion : http://wiki.dlang.org/Review/std.logger 
authored by Robert Schadek.


First I want to say that I want this to be *the* logging library, 
just as I always want a D library to be the best library in the 
world at what it does, as I believe D allows us to do that. I'm 
confident std.logger can become that, so thank you Robert for 
your work.


As for using class-based polymorphism; this doesn't have to mean 
GC memory. The only part of the library code that should have a 
need to allocate a logger class is the lazy initialization in 
`defaultLogger`. If we change this to allocate in global memory, 
then it's entirely up to the user how to allocate logger 
instances. Giving up classes here because of GC means giving up 
classes in no-GC code entirely, which I think is a serious 
overreaction. I think there are reasons to question the 
class-based polymorphism, on grounds such as - do we require that 
`writeLogMsg` is @nogc so we can log in @nogc code? What about 
nothrow? When it comes to performance and the indirect call 
involved, I don't think there's a way around that.


When it comes to GC memory, MultiLogger using an associative 
array is a blocker. However, I don't think it can be elegantly 
fixed as we don't have pluggable allocators for any of our 
standard containers yet. Maybe using an array (perhaps sorted) is 
an acceptable compromise measure if @nogc is deemed a priority.


One thing that really bugs me though, is that `Logger` is an 
abstract class and not an interface. An abstract class should 
only be needed when it has both pure virtual functions as well as 
default functionality that can be conditionally overridden, so 
`Logger` should not be a candidate. It should be rewritten in 
terms of an interface, which enables users to implement logger 
functionality in any of their classes, instead of having to 
dedicate a new class type just to override one virtual function.


I much prefer overloading over the mess of suffixes for the same 
reasons Andrei mentioned.


The library's stance on thread safety needs to be clearly 
defined. Currently, `defaultLogger` is process-wide, which can 
only mean logger instances must be thread-safe. Yet there is no 
mention in the documentation that loggers must be thread-safe, 
and indeed I think most of the default-provided loggers are 
written with no concern for thread safety.


I suggest one of two approaches: 1) make `defaultLogger` TLS and 
rework the documentation so it's clear that each thread must 
manage their own logger, or 2) make it clear that `defaultLogger` 
must be thread-safe, and take extreme care in the 
default-provided loggers that they are indeed thread-safe. Maybe 
a templated base logger class `LockingLogger` or something could 
help here.


The documentation needs a lot of work, but I think anyone can 
help with that. I intend to file a pull request to Robert's fork 
with fixes I could spot; it seems more efficient for both of us 
than posting an endless stream of line comments.


Re: Review: std.logger

2014-07-24 Thread Jakob Ovrum via Digitalmars-d
On Thursday, 24 July 2014 at 23:01:56 UTC, Robert burner Schadek 
wrote:
I do this lazily in a function, because having it global froze 
std.concurrency and std.process unittest. I couldn't figure out 
why.


It could still be initialized lazily, using `emplace`, ala

---
private static __gshared Logger _defaultLogger;

Logger defaultLogger() @safe @nogc
{
static __gshared ubyte[__traits(classInstanceSize, 
StdoutLogger)] buffer;


if(!_defaultLogger) // TODO: thread safety
_defaultLogger = () @trusted { return 
emplace!StdoutLogger(buffer); }();


return _defaultLogger;
}

void defaultLogger(Logger newDefaultLogger) @safe @nogc
{
_defaultLogger = newDefaultLogger;
}
---

As said earlier, I think GC and Logger is a none issue. I mean 
how often has anyone seen a Logger created in a loop over and 
over again.


Some programs want to forego having a GC-heap entirely. That 
means any GC allocation is a no-go.


Class instances don't have to be GC-allocated, so it's not an 
issue to use classes.



nothrow will be hard as std.logger uses format, same for nogc


How often have you seen a formatted log message logged in a loop? 
I'd wager that happens quite often. Using `format` is a no-go as 
it completely thrashes the GC, it needs to use `formattedWrite` 
to write directly to the underlying buffer (such as a file).


Even using `formattedWrite` though, `nothrow` is still a problem, 
and since exceptions are still GC-allocated, it doesn't help with 
@nogc either. The latter is something we can fix in the future 
though.



So you're thinking of a stack array?


No, MultiLogger could manage a non-GC yet still heap-allocated 
array using std.container.array.Array. It uses the C heap 
internally, i.e. malloc, realloc and free. Sortedness can be used 
for searching by name in logarithmic time if desired.


What about the log functions and there implementation as well 
as the Logger specific LogLevel and name?


The log functions don't need to be virtual, only the 
`writeLogMsg` function does, so these implementations can either 
be final member functions of the interface, or UFCS functions as 
I suggested in the corresponding line comment.


The Logger-specific LogLevel and the name do not have to be 
implemented by Logger. Leave it to concrete classes to implement 
those. As an internal aid, an abstract GenericLogger base class 
that manages these properties as member variables (as Logger 
currently does) can help.


Re: Review: std.logger

2014-07-24 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 24 July 2014 at 23:40:56 UTC, Jakob Ovrum wrote:
How often have you seen a formatted log message logged in a 
loop? I'd wager that happens quite often. Using `format` is a 
no-go as it completely thrashes the GC, it needs to use 
`formattedWrite` to write directly to the underlying buffer 
(such as a file).


To eloborate on this: using `format` like std.logger currently 
does, for short-lived strings that are consumed and discared 
almost immediately in a higher stack frame, is extremely 
inefficient as every string needs at least one heap memory 
allocation (though `format` can easily do *multiple* in one 
call). It's a good way to quickly thrash and fragment the GC 
heap, putting an extreme amount of stress on the collector.


Even C has fprintf. If we don't provide efficient formatted 
writing, people will not use our abstractions.


The solution is to use `formattedWrite` for custom allocation 
behaviour. When I've used `formattedWrite` for this kind of 
problem before, it has generally come down to the following 
patterns; let's assume the underlying sink is a file:


 * One solution is to use `formattedWrite` to write to the file 
directly. Of course, Logger doesn't provide an interface for 
writing partial log messages, or writing log messages in chunks, 
so this would require modifying the basic API. Also, 
`formattedWrite` doesn't guarantee any minimum chunk size, so in 
the worst case, it might result in one write operation per 
character, which is very inefficient.


* Another solution is to use `formattedWrite` to write to a 
stack-allocated character buffer, then subsequently pass it to 
`writeLogMsg`. This is a leaky abstraction because it puts an 
arbitrary upper limit on how long log entries can be. A practical 
compromise is to revert to a heap allocation for entries that 
don't fit in the stack buffer, but we can do better;


* The best solution is a hybrid one. Use `formattedWrite` to 
write to a stack-allocated buffer, then whenever it's full, write 
the contents of the buffer to the underlying sink (this is easily 
doable by passing a delegate to `formattedWrite` that sees the 
stack buffer as an upvalue). Yes, this does require modifying the 
basic logger API to support partial writes, but it gives us 
optimal performance.


The last solution gives us no dynamic memory allocations unless 
an exception is thrown, while still minimizing the number of 
writes to the underlying sink, which is important when writes can 
be expensive, such as writes to a file or a socket.


Re: DIP65: Fixing Exception Handling Syntax

2014-07-25 Thread Jakob Ovrum via Digitalmars-d

On Friday, 25 July 2014 at 09:39:23 UTC, Walter Bright wrote:

That can be special cased, too.


Seriously? Where does it end?

catch(MyTemplatedException!true) {
}

Parsing this as a proper type without a trailing identifier is a 
nice feature that a lot of people use, unlike the ghastly catch 
{} feature that nobody uses and should be considered harmful. 
Whether we constrain the former or kill the latter, they're both 
breaking changes. So why are we favouring the *bad* one?


Re: DIP65: Fixing Exception Handling Syntax

2014-07-25 Thread Jakob Ovrum via Digitalmars-d

On Friday, 25 July 2014 at 23:12:33 UTC, Walter Bright wrote:

On 7/25/2014 3:56 PM, David Nadlinger wrote:
Let's just get rid of catch {} which encourages unsafe code 
and be done with it.


We need to stop breaking code.


Either change breaks code. There's no evidence to support that 
catch{} is more commonly used than catch(MyException!true) et al.


Re: Opportunistic worst-case complexity upgrade? aka binary search with `find`

2014-07-26 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 24 July 2014 at 21:08:58 UTC, Jonathan M Davis wrote:

On Thursday, 24 July 2014 at 01:26:48 UTC, Jakob Ovrum wrote:

On Thursday, 24 July 2014 at 01:21:44 UTC, Jakob Ovrum wrote:

-snip-


Another point is that the range types of the two currently 
available sorted containers - RedBlackTree and BinaryHeap - 
are *not* instances of SortedRange. If algorithms working on 
sorted ranges become a thing, it seems like they should be.


Maybe a better approach would be do just have sorted range 
types define find themselves? UFCS would then make it so that 
the best search function for that type would be used (e.g. I 
don't think that binary search is the best method to use a 
red-black tree).


Right, the two tree structures can't be searched properly using a 
generic binary search algorithm.


I don't think having containers define `find` as a member is 
really feasible. `find` is a highly generic function with a 
multitude of forms, and to be interchangeable, every container 
would have to support all these forms. That sounds extremely 
impractical.


However, regardless of that, it could be useful to know whether 
a range is sorted or not in general, and we may want to change 
how we do that so that there's an enum which indicates it 
rather than simply wrapping it in SortedRange (e.g. we know 
that RedBlackTree's range type is sorted, but I doubt that we 
want to always be wrapping it in a SortedRange to show that).


- Jonathan M Davis


The container could simply make its Range type an alias to 
SortedRange!(RangeImpl, pred). It wouldn't cost anything. But, of 
course, as you pointed out, it's not possible for the tree 
structures, at least not without changing something in 
SortedRange.


Maybe SortedRange's search functions should defer to the 
underlying range if the underlying range supports logarithmic 
search, such as by defining `lowerBound` et al. as members of the 
range type. This would cause some duplication of course, as 
currently, `lowerBound` et al. are container primitives. However, 
wouldn't it be the right place for them?


Currently, using `SortedRange`, we can do binary search on a 
*subset* of the original range, as its search functions in turn 
return sorted ranges:


---
auto data = [1, 2, 3, 4, 5].assumeSorted();

auto lower = data.lowerBound(5);
auto target = lower.upperBound(1); // Narrower search area!

assert(target.equal([2, 3, 4]));
---

In the current container model, where they are primitives of the 
container and not the container's range, this is not possible.


Re: Setting array length to 0 discards reserved allocation?

2014-07-26 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 26 July 2014 at 23:06:02 UTC, Andrew Godfrey wrote:

Thereafter can come sub-slice examples and so on.
Does this make sense?


Yes, the reference documentation is pretty terrible with naming 
of various array concepts.


IIRC, when this was discussed in the past, a majority seemed to 
be in favour of using slice and dynamic array for their 
respective concepts instead of the current situation, but I also 
remember there was some opposition (for reason I can't remember). 
A pull request updating the documentation to use slice/dynamic 
array might weed them out ;)


Re: Setting array length to 0 discards reserved allocation?

2014-07-27 Thread Jakob Ovrum via Digitalmars-d

On Sunday, 27 July 2014 at 08:49:43 UTC, Jonathan M Davis wrote:
As defined by the language, T[] is a dynamic array. As great as 
the article is, it was wrong in its use of the terminology, and 
that's what's caused a lot of the confusion and resulted in 
arguments over the difference between a dynamic array and a 
slice (there really isn't any). IIRC, both Walter and Andrei 
stated in that discussion that T[] is a dynamic array as far as 
D is concerned and that's not going to change. The article 
really should be updated to reflect the correct terminology. As 
far as D is concerned a slice and a dynamic array are the same 
thing when it comes to arrays. They're just different names for 
T[], and trying to treat them as different just causes 
confusion.


Conflating both concepts with the same name is why the article 
was so dearly needed in the first place.


Re: Setting array length to 0 discards reserved allocation?

2014-07-27 Thread Jakob Ovrum via Digitalmars-d

On Sunday, 27 July 2014 at 12:03:05 UTC, Jonathan M Davis wrote:
Except that no concepts are being conflated. T[] is the dynamic 
array. There's a block of memory managed by the GC underneath, 
but it's completely hidden from the programmer. It is _not_ the 
dynamic array. It's just a block of memory managed by the GC 
which is used to manage the memory for dynamic arrays, and it 
has a completely different type from T[]. It's not even an 
array in the D sense. The block of memory is referred to by a 
pointer, not a D array.


It's talk of which array owns the memory and the like which 
causes confusion, and talking about the GC-managed block of 
memory as being the dynamic array and the T[] that the 
programmer sees as being the slice is just plain wrong. The T[] 
is both a slice and a dynamic array (because they're the same 
thing), whereas the block of memory is neither. I think that 
the fact that the article tried to call the underlying block of 
memory a dynamic array has caused a lot of unnecessary 
confusion.


- Jonathan M Davis


This very thread is a testament to the fact that no, it's not 
completely hidden, and it is the conflation that causes 
confusion, and clarity only comes when the two concepts are 
explained separately.


This matches my experience when I teach about D's arrays on IRC 
too - people generally feel enlightened after reading the array 
article.


It's debatable whether hamfisting dynamic array capabilities onto 
a simple slice type was a good idea or not (T[new], anyone?), but 
we should be as clear with the current situation as possible. 
Pretending there isn't a problem is ignoring the cries of D 
newbies everywhere. Please stop.




Re: Voting: std.logger

2014-07-28 Thread Jakob Ovrum via Digitalmars-d

On Tuesday, 29 July 2014 at 05:11:33 UTC, Dicebot wrote:

1) Yes / No for inclusion into std.experimental


If modules in std.experimental are completely free to make 
breaking changes, then my vote is a clear yes.


I'm uncertain if std.experimental can carry its own weight in the 
presence of dub, but I guess that's a discussion for another 
thread.



2) Yes / No for inclusion into Phobos in its current state


No.

IMO, both API and implementation are insufficient. Additionally, 
the current state is extremely volatile with sweeping API 
changes being made in the last two weeks or so.


However, review is on-going and at this rate, I'm hopeful it will 
be good enough by the next vote.


3) If you have answered No for (2) :  list of mandatory 
changes that are needed to make you vote Yes


a) The *API* must support minimal dynamic memory allocation for 
the normal execution path. However, theoretical *implementation* 
changes that reduce memory allocation are not a deal-breaker.


b) API must specify a strong stance on threading, whatever the 
form it takes.


c) This one might seem unnecessarily strict, but I think the fact 
that Logger is a class and not an interface smells of poor 
design. I might still be convinced that having it as a class is 
justified, but my current stance is that it must be an interface.



4) Any additional comments for author.


The author is aware of my gripes from Github comments and posts 
in the review thread.


Re: discuss disqus

2014-07-30 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 30 July 2014 at 13:10:35 UTC, Wyatt wrote:

Serious question: what exactly is supplemental documentation?
 In my view, if it's good enough to be considered 
documentation, it belongs in the documentation.  Anything else 
is just pussy-footing around.


Consider information like how to do X with Y. The combinations 
may be endless and opinions will vary about which cases warrant 
mention in the reference documentation. Placing it on a Wiki page 
sidesteps all that. We have to be careful not to clutter up the 
reference documentation with trivial information; it's not a 
tutorial.


Further, as it is, reference documentation can only be updated by 
going through peer review. A Wiki on the other hand would have to 
be moderated after-the-fact and peer review would not be 
guaranteed.


When it comes to asking questions, I agree we have plenty of 
outlets more appropriate than Disqus as it is, including D.learn, 
the IRC channel and StackOverflow.


Disqus just doesn't buy us anything, while the disadvantages are 
numerous.


Re: const after initialization / pointers, references and values

2014-08-20 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 20 August 2014 at 21:26:55 UTC, Philippe Sigaud via 
Digitalmars-d wrote:
If you want reference semantics but do not want to have 
pointers in

your code, yes classes are your best choice.


Certainly the easiest, but I don't think it's always the best. If 
light-weightedness is desired, make the struct contain the 
reference, effectively making the struct a reference type:

---
private struct Data
{
int a;
string b;
double c;
}

/// Lorem ipsum ...
struct UserFacingType
{
private Data* data;
// use data.foo
}
---
Of course, this means UserFacingType.init is essentially `null`, 
just like class references. By using std.typecons.RefCounted, the 
user-facing type can also easily be made a reference-counted 
reference.


Structs can do everything classes can with enough boilerplate. 
Leverage templated types like RefCounted to remove the 
boilerplate. Classes are just an in-built convenience feature to 
handle the boilerplate of virtual functions.


Re: problem creating a 32-bit dll

2014-08-26 Thread Jakob Ovrum via Digitalmars-d

On Tuesday, 26 August 2014 at 14:48:05 UTC, nezih wrote:

Hi everyone,
I am trying to create a 32-bit dll (on windows server 2012 
64-bit) for an odbc driver, but no luck so far.


Are you using DMD32 with OPTLINK? If so, are you sure the first 
exported symbol doesn't accidentally have a leading underscore in 
the resulting DLL? I'm not sure in which DMD release this bug was 
fixed[1], but I've always had to work around it in my own 
OPTLINK-made DLLs.


[1] https://github.com/DigitalMars/optlink/pull/10


Re: problem creating a 32-bit dll

2014-08-26 Thread Jakob Ovrum via Digitalmars-d

On Tuesday, 26 August 2014 at 15:28:32 UTC, nezih wrote:
I use optlink and I use the latest dmd: DMD32 D Compiler 
v2.066.0
And yes I see underscores in front of the exported symbol 
names. What's the workaround? And I just verified that the 
64-bit version doesn't have those leading underscores.


Ah, runtime linking code rarely accounts for leading underscores 
(the so-called Windows system convention), so that is probably 
your problem.


First, make sure the symbols are marked extern(C) and not 
extern(Windows) or extern(System).


The workaround I usually use is simply prepending a dummy symbol 
to each exported one. If the exported C symbols are *not* mixed 
in, just manually place a dummy symbol at the beginning of the 
module:


---
export extern(C) void __optlinkdummy() {}
---

If they are mixed in through a mixin template or a string mixin, 
use pragma(mangle, ...) or string concatenation, respectively, to 
place a uniquely named dummy export before each proper export. 
This robustly ensures that your proper export is never the first 
exported symbol.


This is supposed to be fixed in the latest OPTLINK source code, 
so it's tragic that DMD 2.066 ships with an outdated version that 
still has this terrible bug :(


Re: Voting: std.logger

2014-08-30 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 30 August 2014 at 02:11:49 UTC, Dicebot wrote:


Jakob Ovrum


The *API* must support minimal dynamic memory allocation for
the normal execution path. However, theoretical *implementation*
changes that reduce memory allocation are not a deal-breaker.

This seems to be addressed but though it is desired to verify 
it via @nogc unittest block which uses stub no-op logger (to 
verify that nothing in between allocates). One place were GC 
allocations is unavoidable is core.d:1628 - it will always 
create FileLogger first and allow assigning custom one later. 
Is there any way to circumvent it?


Yes - split the `stdlog` property into a getter and a setter. 
Then if the setter is called first (with a non-null reference), 
the getter never gets to allocate the default instance. I pointed 
this out in a line comment before, but I guess it disappeared due 
to the name change...


Also, as I said in the line comment, it doesn't need to 
GC-allocate, it can allocate in global memory or TLS using 
emplace (which of them is appropriate depends on the threading 
model, I guess...). If Andrei's reference-counting suggestion is 
implemented, then depending on the details, it's possible that 
the default logger could be allocated on the C heap instead of 
the GC heap as well, managed by RC.


Re: Voting: std.logger

2014-08-30 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 30 August 2014 at 13:37:17 UTC, Dicebot wrote:
On Saturday, 30 August 2014 at 13:35:57 UTC, H. S. Teoh via 
Digitalmars-d wrote:
How do the remaining issues break down into QoI that can be 
deferred

to a future release? -- Andrei

What is QoI? I am not familiar with this abbreviation


Quality of Implementation.


And how can one break issues into quality of implementation? :O 
I have literally no idea what Andrei means.


Implementation issues can be fixed later as long as the API 
allows for it, so we should focus on the latter.


Re: Communication with other languages via wrappers

2014-09-03 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 3 September 2014 at 22:23:48 UTC, Xavier Bigand
wrote:

Le 21/08/2014 15:20, seany a écrit :

I am starting this thread to quench my thirst for knowledge.

I notice, that the existing wrappers to other languages are:

C: D can natively interface to C
C++  : Some interfacing possible
Lua  : There is LuaD and DLua
Objective C  : This : 
https://michelf.ca/projects/d-objc-bridge/


Would someone like to add some more?


As I know LuaD and DLua doesn't allow D to be interfaced with 
Lua code. LuaD and DLua are wrappers of the Lua library written 
in C, that not exactly the same thing. So LuaD and DLua help 
you to make your application extensible throw the Lua scripting 
language (it replace a plugin system).


Not entirely sure what you're saying here, but it goes both ways.
LuaD also helps you write shared libraries that can be loaded
from a Lua application.


Re: Can I pass a function by parameter?

2014-09-07 Thread Jakob Ovrum via Digitalmars-d

On Sunday, 7 September 2014 at 21:02:16 UTC, John Colvin wrote:

bool g(int n) { ... }
f(arr, g);


This will fail if `g` is a function pointer, such as when `g` is 
declared at module-level scope. In that case, it has to be 
explicitly converted to a delegate:


---
import std.functional : toDelegate;

int f(in int[] arr, bool delegate(int) func);
bool g(int n) { ... }
f(arr, toDelegate(g));
---

Alternatively, make `f` receive a function pointer instead of a 
delegate:


---
int f(in int[] arr, bool function(int) func);
bool g(int n) { ... }
f(arr, g);
---


Re: Can I pass a function by parameter?

2014-09-07 Thread Jakob Ovrum via Digitalmars-d

On Sunday, 7 September 2014 at 21:31:11 UTC, AsmMan wrote:
Thank you too. Btw, why the  operator in this syntax? I used 
to think ref keyword sort of C's T** and  operator is 
neeeded.. or is it because f can be a function called without 
pass any parameter?


In D, the address-of operator has to be used to get a function 
pointer or delegate from a function or member function. This is 
unlike C and C++, where the function is implicitly convertible to 
its function-pointer type.


This difference in rules may be because D has functions that can 
be called without parentheses:


---
int foo() { return 42; }

// Note: `bar` is an overload set.
void bar(void function() a) {}
void bar(int a) {}

void main()
{
assert(foo() == 42);

// Nullary functions can also be called without parentheses.
assert(foo == 42);

bar(foo); // If function pointers worked like in C, which 
overload should be called?

}
---


Re: Can I pass a function by parameter?

2014-09-07 Thread Jakob Ovrum via Digitalmars-d

On Sunday, 7 September 2014 at 21:42:31 UTC, Jakob Ovrum wrote:

void bar(void function() a) {}


s/void function() a/int function() a/


Re: Can I pass a function by parameter?

2014-09-07 Thread Jakob Ovrum via Digitalmars-d

On Monday, 8 September 2014 at 03:37:45 UTC, deadalnix wrote:

In fact the distinction is done by C and C++ only.


And by D.


Re: Can I pass a function by parameter?

2014-09-07 Thread Jakob Ovrum via Digitalmars-d

On Monday, 8 September 2014 at 03:01:40 UTC, AsmMan wrote:

I got it. Why it doesn't works if foo is a method?


Taking the address of a method/member function yields a delegate, 
not a function pointer. Delegates are fat pointers; they contain 
a pointer to the function as well as a pointer to the context 
(the context is a hidden argument to the function, such as the 
this-reference of a class method). The context pointer is needed 
when calling the function, so they are encapsulated in one 
convenient type, which is the delegate type.


Function pointers can be converted to delegates through a simple 
wrapper function (which is how std.functional.toDelegate achieves 
it), but delegates cannot be wrapped by a function pointer 
without introducing additional parameters to the function in 
order to pass the context pointer. Additionally, the *type* of 
the context pointer is erased, which is immensely handy as it 
means delegates with different contexts can be freely mixed, but 
it means there's no way to know the type of the context (such as 
a class type) just from the delegate, so there is no generic 
`toFunctionPointer` function that would roughly do the inverse of 
`toDelegate`. Each case has to be dealt with on a case-by-case 
basis.


As function pointers can be converted to delegates, delegates are 
the more versatile of the two. I recommend using delegates unless 
there is a good reason not to.


Re: Can I pass a function by parameter?

2014-09-08 Thread Jakob Ovrum via Digitalmars-d

On Monday, 8 September 2014 at 06:23:40 UTC, deadalnix wrote:

On Monday, 8 September 2014 at 05:04:21 UTC, Jakob Ovrum wrote:
Function pointers can be converted to delegates through a 
simple wrapper function (which is how 
std.functional.toDelegate achieves it), but delegates cannot 
be wrapped by a function pointer without introducing 
additional parameters to the function in order to pass the 
context pointer.


Actually, this is possible using a trampoline.


True. AFAICT, a cross-platform, cross-architecture generic 
function for that is non-trivial and might be a neat candidate 
for Phobos.


Re: @nogc, exceptions, generic containers... Issues.

2014-09-09 Thread Jakob Ovrum via Digitalmars-d

On Monday, 8 September 2014 at 15:55:53 UTC, monarch_dodra wrote:
A particularly relevant example of this issue is `RefCounted`: 
This struct uses malloc to ref count an object, give a 
deterministic life cycle, and avoid the GC. Yet, since malloc 
can fail, it does this:

_store = cast(Impl*) enforce(malloc(Impl.sizeof));
Can you see the issue? This object which specifically avoids 
using the GC, end up NOT being @nogc.


Although it's tangential to the issue at large, this particular 
code is wrong anyway. It should be using `onOutOfMemoryError` 
(which should be @nogc), otherwise the allocation of the 
exception is likely to fail just as `malloc` did.


@nogc and exceptions

2014-09-11 Thread Jakob Ovrum via Digitalmars-d
There is one massive blocker for `@nogc` adoption in D library 
code: allocation of exception objects. The GC heap is an ideal 
location for exception objects, but `@nogc` has to stick to its 
promise, so an alternative method of memory management is 
desirable if we want the standard library to be widely usable in 
`@nogc` user code, as well as enabling third-party libraries to 
apply `@nogc`. If we don't solve this, we'll stratify D code into 
two separate camps, the GC-using camp and the `@nogc`-using camp, 
each with their own set of library code.


I can think of a couple of ways to go:

1) The most widely discussed path is to allocate exception 
instances statically, either in global memory or TLS. Currently, 
this has a few serious problems:


  1a) If the exception is chained, that is, if the same exception 
appears twice in the same exception chain - which can easily 
happen when an exception is thrown from a `scope(exit|failure)` 
statement or from a destructor - the chaining mechanism will 
construct a self-referencing list that results in an infinite 
loop when the chain is walked, such as by the global exception 
handler that prints the chain to stderr. This can easily be 
demonstrated with the below snippet:


---
void main()
{
static immutable ex = new Exception();
scope(exit) throw ex;
throw ex;
}
---

Amending the chaining mechanism to simply *disallow* these chains 
would neuter exception chaining severely, in fact making it more 
or less useless: it's not realistically possible to predict which 
exceptions will appear twice when calling code from multiple 
libraries.


  1b) Exceptions constructed at compile-time which are then later 
referenced at runtime (as in the above snippet) must be immutable 
(the compiler enforces this), as this feature only supports 
allocation in global memory, not in TLS. This brings us to an 
unsolved bug in the exception mechanism - the ability to get a 
mutable reference to an immutable exception without using a cast:


---
void main()
{
static immutable ex = new Exception();
try throw ex;
catch(Exception e) // `e` is a mutable reference
{
// The exception is caught and `e` aliases `ex`
}
}
---

Fixing this would likely involve requiring 
`catch(const(Exception) e)` at the catch-site, which would 
require users to update all their exception-handling code, and if 
they don't, the program will happily compile but the catch-site 
no longer matches. This is especially egregious as error-handling 
code is often the least tested part of the program. Essentially 
D's entire exception mechanism is not const-correct.


  1c) Enhancing the compiler to allow statically constructing in 
TLS, or allocating space in TLS first then constructing the 
exception lazily at runtime, would allow us to keep throwing 
mutable exceptions, but would seriously bloat the TLS section. We 
can of course allocate shared instances in global memory and 
throw those, but this requires thread-safe code at the catch-site 
which has similar problems to catching by const.


2) The above really shows how beneficial dynamic memory 
allocation is for exceptions. A possibility would be to allocate 
exceptions on a non-GC heap, like the C heap (malloc) or a 
thread-local heap. Of course, without further amendments the onus 
is then on the catch-site to explicitly manage memory, which 
would silently break virtually all exception-handling code really 
badly.


However, if we assume that most catch-sites *don't* escape 
references to exceptions from the caught chain, we could 
gracefully work around this with minimal and benevolent breakage: 
amend the compiler to implicitly insert a cleanup call at the end 
of each catch-block. The cleanup function would destroy and free 
the whole chain, but only if a flag indicates that the exception 
was allocated with this standard heap mechanism. Chains of 
exceptions with mixed allocation origin would have to be dealt 
with in some manner. If inside the catch-block, the chain is 
rethrown or sent in flight by a further exception, the cleanup 
call would simply not be reached and deferred to the next 
catch-site, and so on.


Escaping references to caught exceptions would be undefined 
behaviour. To statically enforce this doesn't happen, exception 
references declared in catch-blocks could be made implicitly 
`scope`. This depends on `scope` actually working reasonably 
well. This would be the only breaking change for user code, and 
the fix is simply making a copy of the escaped exception.


Anyway, I'm wondering what thoughts you guys have on this nascent 
but vitally important issue. What do we do about this?


Re: It turns out it's quite hard to have @safe pure nothrow functions. Oh, and const.

2014-09-12 Thread Jakob Ovrum via Digitalmars-d

On Friday, 12 September 2014 at 09:53:45 UTC, Atila Neves wrote:
This happens to me all the time. I write a function, stick the 
aforementioned attributes on as a default then let the compiler 
tell me when I can't.


That happens a lot more often than I thought it would. Pretty 
much anytime I call a Phobos function I have to remove at least 
one of them but usually all three.


Is it similar for everyone else? Is it considered a problem?


Phobos still hasn't been fully annotated since these attributes 
were introduced, but we are making progress. For one, I believe 
we got @safe std.stdio recently, which should be a big boost for 
@safe adoption in general.


It is slowly getting better. Pull requests are welcome.

The other thing is I frequently have to unconstify my 
variables to get them accepted by Phobos functions as well.


D's const is very different from C++'s const. It's tempting to 
use in the same situations because of superficial similarities, 
but D's const should only be used when immutable is in the 
picture. D simply doesn't have the equivalent of C++'s const 
(which is intentional), despite their similar names.


That said, there are fundamental issues with const and immutable 
that have yet to be resolved - for example, given an immutable 
container or a const reference to a container, it's not possible 
to get a head-mutable range over it for iteration. This is 
different from in-built slices which are conveniently convertible 
from const(T[]) to const(T)[], something that is not expressible 
with user-defined types at the moment.


Further, `inout` does not support considering callback parameters 
to be out parameters:


struct S
{
int* p;

inout(int)* foo() inout { return p; } // OK

void bar(void delegate(inout int*) dg) inout { // Not 
supported

dg(p);
}
}

Both of these issues have been discussed before and IIRC, 
consensus seemed to be that we do want to do something about them.


Re: It turns out it's quite hard to have @safe pure nothrow functions. Oh, and const.

2014-09-12 Thread Jakob Ovrum via Digitalmars-d

On Friday, 12 September 2014 at 13:11:19 UTC, Kagamin wrote:

On Friday, 12 September 2014 at 10:19:27 UTC, Jakob Ovrum wrote:
Further, `inout` does not support considering callback 
parameters to be out parameters:


struct S
{
   int* p;

   inout(int)* foo() inout { return p; } // OK

   void bar(void delegate(inout int*) dg) inout { // Not 
supported

   dg(p);
   }
}


Looks like it works: http://dpaste.dzfl.pl/04a33be05658


Now try calling it: http://dpaste.dzfl.pl/bbd02a4d61df


Re: @nogc and exceptions

2014-09-12 Thread Jakob Ovrum via Digitalmars-d

On Friday, 12 September 2014 at 11:03:09 UTC, monarch_dodra wrote:
I think option b) is the right direction. However, I don't 
think it is reasonable to have the catch code be responsible 
for the cleanup proper, as that would lead to a closed design 
(limited allocation possibilities).


Exceptions using other alocators simply don't set the flag.

I like the option of having exception allocators that can 
later be explicitly called in a release all exceptions style, 
or plugged into the GC, to be cleaned up automatically like any 
other GC allocated exception. This would make the exceptions 
themselves still @nogc, but the GC would have a hook to 
(potentially) collect them. For those that don't want that, 
then they can make calls to the cleanup at deterministic times.


We can't change existing instances of `throw` to use such a 
manually managed heap without silently causing user code to leak.


Finally, if somebody *does* want to keep exceptions around, he 
would still be free to do so *provided* he re-allocates the 
exceptions himself using a memory scheme he chooses to use (a 
simple GC new, for example).


Yes, but we can't let existing code that escapes exceptions run 
into memory corruption because we changed the allocator. We need 
`scope`.


... well, either that, or have each exception carry a callback 
to its allocator, so that catch can do the cleanup, regardless 
of who did the allocation, and how. GC exceptions would have no 
callback, meaning a catch would still be @nogc. An existing 
code that escapes exceptions would not immediately break.


I think this would depend on having multiple proposed exception 
allocation strategies in the first place.


We know when the cleanup happens and we roughly know the 
allocation pattern (exceptional paths are rarely hit etc.), so I 
think we should focus on finding/creating an allocator ideal for 
this pattern, then apply it to Phobos.


Re: @nogc and exceptions

2014-09-12 Thread Jakob Ovrum via Digitalmars-d
On Friday, 12 September 2014 at 11:38:18 UTC, Andrej Mitrovic via 
Digitalmars-d wrote:
On 9/12/14, Jakob Ovrum via Digitalmars-d 
digitalmars-d@puremagic.com wrote:

the chaining mechanism will
construct a self-referencing list that results in an infinite
loop when the chain is walked


Can we amend the spec to say self-referencing is ok? Then we 
could

make the default exception handler *stop* if it finds a
self-referencing exception (e.g. for stack traces), and for 
custom
user code which walks through exceptions it would either have 
to be

fixed.

We could also provide a helper function for walking through 
exceptions:


try
{
...
} catch (Exception ex)
{
// some UFCS or object.d built-in method which
// stops walking when .next is this
foreach (caught; ex.walk)
{
}
}

Or does the problem have a bigger scope than just walking?


The exception chain would be unable to chain further exceptions. 
Each exception in the chain needs its own unique `next` pointer.


Also, the two links to the same exception could appear anywhere 
in the list. I think some sort of caching of exceptions already 
encountered would be required, which is a lot slower and more 
complex than the existing mechanism.


Re: @nogc and exceptions

2014-09-12 Thread Jakob Ovrum via Digitalmars-d

On Friday, 12 September 2014 at 12:47:46 UTC, Vladimir Panteleev
wrote:

On Friday, 12 September 2014 at 03:37:10 UTC, Jakob Ovrum wrote:

I can think of a couple of ways to go:


1) The most widely discussed path is to allocate exception 
instances statically, either in global memory or TLS. 
Currently, this has a few serious problems:


Another problem with this is that you'll need to change every 
instance of new FooException to something else.


I don't think this is a big problem, `@nogc` will tell you where
the allocations are, and it's fairly easy to just grep and
replace. It's also worth noting that code using enforce et al.
could be updated automatically.

Further, you only need to do this if you want your library code
to be `@nogc`. Existing code using the GC-heap will keep working
(except for the `scope` thing I proposed...).


Re: @nogc and exceptions

2014-09-12 Thread Jakob Ovrum via Digitalmars-d
On Friday, 12 September 2014 at 16:33:50 UTC, Dmitry Olshansky 
wrote:

Agreed.

I think that the total amount of live (not garbage) exceptions 
on heap is small for any typical application. Thus just special 
casing the hell out of exception allocation in the GC (and 
compiler) is IMO perfectly satisfactory hack.


We can't use the GC as the whole point is to mark library code 
`@nogc`. It should work even if the user has ripped the GC out of 
druntime with a custom build.


Re: @nogc and exceptions

2014-09-12 Thread Jakob Ovrum via Digitalmars-d

On Friday, 12 September 2014 at 21:36:31 UTC, Johannes Pfau wrote:
I think if we could avoid dynamic allocations for most 
exceptions
completely that'd be better. IIRC some people said that 
exceptions are
mainly slow because of memory allocation. So if we could avoid 
that,

there are more benefits.


While we should ideally make the exception mechanism as fast as 
possible, it mustn't be a priority, lest we compromise more 
important parts of the design for the red herring that is 
performance.


If a program is slow because of exception handling it's not using 
exceptions correctly. It should replace that part of the code 
with a solution that uses error codes. This is the mantra that 
goes for all languages with exceptions that I know, except Python 
and maybe Java.


Also, we know the approximate size of exceptions and their 
allocation pattern. An efficient heap allocator could be designed 
to take advantage of this.


That's not to say I'm against any non-heap solution if we can 
think of something really good, but we should keep our priorities 
straight.


I suggest looking at the C++ implementation. There's the 
throw-by-value
catch-by-reference idiom. C++ must store/copy this exception 
somewhere,

maybe they have a clever solution.

(We basically need some fixed-size per thread memory where we 
can store
the exception and stack trace info. But we need a fallback 
because of

exception chaining or big exceptions.)


I think this is essentially global storage allocation. C++ does 
not do exception chaining so this is much more viable there.


Also, when we decide to use TLS instead of the mess that would be 
shared exceptions, we introduce a massive chunk of required data 
for each new thread in every application that depends on Phobos 
and/or other libraries using the new exception allocator.


Re: It turns out it's quite hard to have @safe pure nothrow functions. Oh, and const.

2014-09-13 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 13 September 2014 at 19:58:16 UTC, Kagamin wrote:
On Saturday, 13 September 2014 at 18:36:53 UTC, Timon Gehr 
wrote:

On 09/13/2014 07:48 PM, Kagamin wrote:
On Saturday, 13 September 2014 at 16:51:09 UTC, Timon Gehr 
wrote:

s.bar((int* p){ ++*p; });


Huh? inout is for functions, which don't modify their 
arguments.


With Jakob's code working, this would not be warranted.


Huh? See rationale in 
https://issues.dlang.org/show_bug.cgi?id=1961


The function doesn't modify `p` - it's modified by a callback 
that was accepted because it's known at the call-site that `p` is 
modifiable.


This is necessary for `inout` to work with callback functions, 
such as with internal iteration (i.e. `opApply`). It can be 
worked around exactly the same way you would work around it with 
functions that return a value - by duplicating the function. It 
is essentially the same problem and thus `inout` could easily be 
used to fix it.


Re: @nogc and exceptions

2014-09-13 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 13 September 2014 at 08:19:10 UTC, Marc Schütz wrote:
On Friday, 12 September 2014 at 21:31:45 UTC, Johannes Pfau 
wrote:

Am Fri, 12 Sep 2014 12:59:22 +
schrieb Marc Schütz schue...@gmx.net:
Related: Last time I checked the runtime caches unwinding or 
stack trace information in the exception. It does this even 
for immutable exceptions...


Yes, in order to avoid allocating a stack trace helper you 
need to cast
the exception from its .init property, IIRC. There's some code 
in
druntime which does that (the out-of-memory error handling 
code).


That's not what I mean, please see here:
http://forum.dlang.org/thread/ftakrucgtfcicfbkz...@forum.dlang.org#post-xmvzmufjywcsxviooivl:40forum.dlang.org


Indeed the entire exception mechanism does not account for 
immutability at all which is not surprising considering it was 
implemented in the days of D1 and there's a lot of type erasure 
going on when druntime functions are called, but it does mean any 
sighting of a non-mutable exception anywhere is a big red flag 
until we overhaul exceptions to account for immutability.


Re: C++ interop - what to do about long and unsigned long?

2014-09-14 Thread Jakob Ovrum via Digitalmars-d
On Sunday, 14 September 2014 at 04:26:30 UTC, Andrei Alexandrescu 
wrote:

On 9/13/14, 8:43 PM, Manu via Digitalmars-d wrote:
I agree. It should be the default in all cases, as unanimously 
agreed by

this community, and overruled by Andrei post-implementation.


There was no unanimity. -- Andrei


+1. I like the status quo except I regret that there's no nice 
way to express non-final as I'm a big fan of using the 
`attribute:` syntax.


Re: Escaping the Tyranny of the GC: std.rcstring, first blood

2014-09-15 Thread Jakob Ovrum via Digitalmars-d
On Monday, 15 September 2014 at 05:50:36 UTC, Andrei Alexandrescu 
wrote:
and have it be either refcounted or classic depending on the 
definition of String. With a user-defined String, you need:


String s = String(abc);


The following works fine:

RCString s = abc;

It will call RCString.this with abc. The problem is passing 
string literals or slices to functions that receive RCString.


Re: Escaping the Tyranny of the GC: std.rcstring, first blood

2014-09-15 Thread Jakob Ovrum via Digitalmars-d
On Monday, 15 September 2014 at 02:26:19 UTC, Andrei Alexandrescu 
wrote:
So, please fire away. I'd appreciate it if you used RCString in 
lieu of string and note the differences. The closer we get to 
parity in semantics, the better.


It should support appending single code units:

---
alias String = RCString;

void main()
{
String s = abc;

s ~= cast(char)'0';
s ~= cast(wchar)'0';
s ~= cast(dchar)'0';

writeln(s); // abc000
}
---

Works with C[], fails with RCString. The same is true for 
concatenation.


Re: Escaping the Tyranny of the GC: std.rcstring, first blood

2014-09-15 Thread Jakob Ovrum via Digitalmars-d

On Monday, 15 September 2014 at 09:53:28 UTC, Robert burner
Schadek wrote:
On Monday, 15 September 2014 at 02:26:19 UTC, Andrei 
Alexandrescu wrote:


The road there is long, but it starts with the proverbial 
first step. As it were, I have a rough draft of a 
almost-drop-in replacement of string (aka immutable(char)[]). 
Destroy with maximum prejudice:


http://dpaste.dzfl.pl/817283c163f5



I haven't found a single lock, is single threading by design or 
is thread-safety on your todo?


There's no use of `shared`, so all data involved is TLS.


Re: Escaping the Tyranny of the GC: std.rcstring, first blood

2014-09-15 Thread Jakob Ovrum via Digitalmars-d

On Monday, 15 September 2014 at 11:53:15 UTC, Robert burner
Schadek wrote:

On Monday, 15 September 2014 at 10:13:28 UTC, Jakob Ovrum wrote:

On Monday, 15 September 2014 at 09:53:28 UTC, Robert burner


I haven't found a single lock, is single threading by design 
or is thread-safety on your todo?


There's no use of `shared`, so all data involved is TLS.


Then it must be made sure that send and receive work properly.


They do. They only accept shared or immutable arguments (or
arguments with no mutable indirection).


Re: Escaping the Tyranny of the GC: std.rcstring, first blood

2014-09-15 Thread Jakob Ovrum via Digitalmars-d
On Monday, 15 September 2014 at 12:47:08 UTC, Robert burner 
Schadek wrote:

On Monday, 15 September 2014 at 12:11:14 UTC, Jakob Ovrum wrote:

There's no use of `shared`, so all data involved is TLS.


Then it must be made sure that send and receive work properly.


They do. They only accept shared or immutable arguments (or
arguments with no mutable indirection).


compiler says no: concurrency.d(554): Error: static assert  
Aliases to mutable thread-local data not allowed.


I used the std.concurrency example


Yes, that was my point. std.concurrency handles it correctly - 
there's no unsafe memory sharing going on with RCString's 
implementation.


If you are suggesting we somehow make this work so it can be a 
drop-in replacement for `string`:


I don't think that should be implicitly supported.

One method would be to support shared(RCString). This isn't very 
practical for this use-case, as since atomic reference counting 
is super slow, you wouldn't want to be using shared(RCString) 
throughout your program. So you'd have to make a copy on each 
side (unshared - shared, then send, then shared - unshared) 
which is one copy more than necessary and would still require 
support for shared(RCString) which is non-trivial.


Another option would be to hardcode support for RCString in 
std.concurrency. This would make the copy hidden, which would go 
against good practices concerning arrays in D, and not very 
useful for @nogc if the copy has to be a GC copy. Additionally, 
RCString's interface would need to be compromised to allow 
constructing from an existing buffer somehow.


Maybe the right solution involves integration with 
std.typecons.Unique. Passing an instance of Unique!T to another 
thread is something std.concurrency should support, and RCString 
could be given a method that returns Unique!RCString if the 
reference count is 1 and errors otherwise. Unique's current 
implementation would have to be overhauled to carry its payload 
in-situ instead of on the GC heap like it currently does, but 
that's something we should do regardless.


Re: Escaping the Tyranny of the GC: std.rcstring, first blood

2014-09-15 Thread Jakob Ovrum via Digitalmars-d
On Monday, 15 September 2014 at 02:26:19 UTC, Andrei Alexandrescu 
wrote:

http://dpaste.dzfl.pl/817283c163f5


The test on line 267 fails on a 32-bit build:

rcstring.d(267): Error: cannot implicitly convert expression 
(38430716820228232L) of type long to uint


Hosting it as a Gist on Github[1] might be an idea, as then the 
same link will be relevant after the code is updated, and people 
can post line comments. It doesn't support building and running 
the code online, but dpaste.dzfl.pl's old FE version (2.065) 
doesn't support the code anyway.


[1] https://gist.github.com/


Re: Library Typedefs are fundamentally broken

2014-09-16 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 17 September 2014 at 02:57:03 UTC, Freddy wrote:

When you have separate 2 typedefs of the exact same type, they
are equal.While this maybe able to be solved with
Typedef!(Typedef!(...)) different modules typedef ing the same
type (most likely build-in types) would have their typedef be
equivalent thereby degrading the purpose of typedef.
---
import std.typecons;

alias meter = Typedef!float;
alias feet = Typedef!float;
static assert(!is(meter==feet));
---
Your thoughts?


`Typedef` takes a second argument that can make it unique. It's 
all in the docs.


Re: Library Typedefs are fundamentally broken

2014-09-18 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 17 September 2014 at 16:32:04 UTC, Dicebot wrote:
On Wednesday, 17 September 2014 at 10:00:31 UTC, Jack Applegame 
wrote:

You can use module name and line number as unique tag.


This is exactly what I would have expected as default 
behaviour. Is anyone aware why this counter appoach was used 
instead?


It's a deceivingly bad default. See the comments in the PR that 
introduced Typedef[1].


[1] https://github.com/D-Programming-Language/phobos/pull/300


Re: Remove dlang.org/library/ from search results?

2014-09-18 Thread Jakob Ovrum via Digitalmars-d
On Friday, 19 September 2014 at 04:37:22 UTC, Vladimir Panteleev 
wrote:
Yes, listing them in robots.txt, which was what I suggested. 
I'm not saying we should actually remove them from the website 
:)


We already have /phobos-prerelease/ and /library-prerelease/ in 
robots.txt:

http://dlang.org/robots.txt


I think we should do it, but robots.txt is tracked by the git 
repository, so might as well continue this in a PR?


Re: @nogc and exceptions

2014-09-19 Thread Jakob Ovrum via Digitalmars-d

On Friday, 19 September 2014 at 07:57:24 UTC, Dicebot wrote:
I am obviously in favor of simply calling recurrent mutable 
exception chains illegal (probably even immutable ones until we 
fix const correctness of druntime exception handling).


Reason is simple : it doesn't require any changes in existing 
code and is exactly the way we already do it in Sociomantic :)


To make it reliable Exception chain may need to be updated to 
doubly-linked list to be able to efficiently verify that new 
exception is not already present in the chain. I don't see any 
costly overhead implications from that though.


That might be sufficient for a particular application like 
Sociomantic's, but it's not sufficient for library code in 
general. Such chains aren't logic errors and can easily occur in 
the wild.


The point of exception chaining is so exceptions can be thrown in 
destructors and such. In library code, these destructors don't 
know what exception is in flight, so they can only assume it 
could be any exception. If self-referencing chains were illegal 
and exceptions were statically allocated, then the conclusion is 
that these destructors can't throw anything after all, because 
that exception might already be in flight. As such, exception 
chaining would be completely useless.


Re: Library Typedefs are fundamentally broken

2014-09-19 Thread Jakob Ovrum via Digitalmars-d

On Friday, 19 September 2014 at 11:14:06 UTC, Dicebot wrote:

On Friday, 19 September 2014 at 04:44:07 UTC, Jakob Ovrum wrote:

On Wednesday, 17 September 2014 at 16:32:04 UTC, Dicebot wrote:
On Wednesday, 17 September 2014 at 10:00:31 UTC, Jack 
Applegame wrote:

You can use module name and line number as unique tag.


This is exactly what I would have expected as default 
behaviour. Is anyone aware why this counter appoach was used 
instead?


It's a deceivingly bad default. See the comments in the PR 
that introduced Typedef[1].


[1] https://github.com/D-Programming-Language/phobos/pull/300


Yes, this is a problem. But how is that possibly worse than 
existing implementation which gives wrong results in 100% of 
cases? file/line cookie approach has issues but it is best we 
can get with existing language support.


`Typedef` clearly comes with a big caveat that isn't apparent 
from just reading user code. The documentation has to be read, 
and the documentation clearly states that the cookie parameter 
has to be used to get unique types. It's much less surprising to 
have it generate unique types only when explicitly given a cookie 
than having it sometimes make unique types and sometimes not 
depending on complex conditions.


Maybe `Typedef` could be neatly fixed by making it a mixin 
template?


Re: RFC: reference counted Throwable

2014-09-20 Thread Jakob Ovrum via Digitalmars-d
On Saturday, 20 September 2014 at 14:31:36 UTC, Adam D. Ruppe 
wrote:
How often do you store an exception reference anyway that 
escapes a catch block? I think all this talk is overkill to 
solve a non-problem in 99% of practice.



Correct me if I'm wrong, but aren't *all* exceptions in a 
particular thread generally unreferenced at the end of a 
catch() block, unless the programmer explicitly escaped that 
reference?


If so, we don't need refcounting! Here's my solution:


I proposed something very similar in this thread[1], except I 
proposed a solution that is fully backwards-compatible except the 
rare case when exceptions are escaped, in which case it causes a 
compile-time error. Might be worth a look.


I don't think it's acceptable that code using Phobos is suddenly 
leaking until they add the new manual cleanup call.


[1] 
http://forum.dlang.org/post/stlslhjndgugecvmb...@forum.dlang.org


Re: Library Typedefs are fundamentally broken

2014-09-20 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 20 September 2014 at 13:49:58 UTC, Marco Leise wrote:

Am Sat, 20 Sep 2014 06:32:38 +
schrieb Vladimir Panteleev vladi...@thecybershadow.net:

On Saturday, 20 September 2014 at 04:52:58 UTC, Andrei 
Alexandrescu wrote:

 [snip]

Um, why not use __FILE__ / __LINE__ (as default values for 
template parameters) as cookies?


It has this nasty imperfection that it breaks as soon as you
define two Typedefs on the same line. Which noone ever does
except maybe for an obfuscated coding scenario, but still it
raises my OCD level.


https://github.com/D-Programming-Language/phobos/pull/300#issuecomment-3329507


Re: scope() statements and return

2014-10-03 Thread Jakob Ovrum via Digitalmars-d
On Friday, 3 October 2014 at 04:52:24 UTC, ketmar via 
Digitalmars-d wrote:

On Fri, 03 Oct 2014 04:40:53 +
deadalnix via Digitalmars-d digitalmars-d@puremagic.com wrote:

The throw thing is rather stupid, as the scope statement can 
call arbitrary function that can itself throw.
that's why you'd better use collectException() there, i 
presume. ;-)


btw: shouldn't compiler check and reject code that calls 
no-nothrow

functions in scope(...)? bug/ER?


No, just like destructors can throw, scope statements can throw 
too. That's why we have exception chaining.


Re: scope() statements and return

2014-10-06 Thread Jakob Ovrum via Digitalmars-d

On Monday, 6 October 2014 at 16:55:39 UTC, monarch_dodra wrote:
For the sake of argument, do you have any examples where a 
program has used chaining?


I use explicit chaining in a couple of my libraries, i.e. code 
like:


---
try foo();
catch(FooException e)
{
throw new BarException(foobar, e);
}
---

However, the whole point is implicit chaining, which is where the 
language and runtime kicks in. Look through your own 
scope(exit|failure) blocks and struct destructors - are they all 
nothrow?


If not, you are using exception chaining.


Re: std.experimental.logger formal review round 3

2014-10-10 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 11 October 2014 at 03:41:08 UTC, Dicebot wrote:
I don't see critical objections so far and this will move to 
voting stage this weekend. Please hurry up if you want to say 
something bad :)


Attributes need to be applied thoroughly. Even if most uses will 
be through the base class `Logger`, it's still useful to have 
stronger guarantees through a derived class reference. This is 
particularly important because it's an important design decision 
to choose which attributes to apply to `Logger`'s methods.


@trusted is used everywhere instead of properly using @safe and 
minimized @trusted. I think this is the third time I point this 
out...


The multiloggers are a complete mess. There's both `ArrayLogger` 
and `MultiLogger`, and while `ArrayLogger` has simple O(n) 
operations, `MultiLogger` is a disaster: insertion iterates all 
elements twice and sorts the entire collection on every call, and 
removal iterates all elements once, then does binary search 
twice. Once using `SortedRange`'s search, and once using its own 
binary search algorithm. It also contains debug code that writes 
to stdout. Neither type adheres to the Phobos container concept, 
instead the underlying array is exposed as a public, undocumented 
field. `string` is used instead of `const(char)[]` for search and 
removal operations.


The implementation of `Logger` has several performance problems. 
`Logger` provides default behaviour that allocates GC memory 
multiple times for even the simplest log messages through the 
`Appender`. I don't think this behaviour should be encouraged by 
putting it in the root logger class, and besides, it can be made 
much more intelligent than just using a new appender for each 
message.


Another issue is that the way it's written currently, 
`writeLogPart` is called a lot more often than necessary, without 
any opportunity for optimization within `formattedWrite`, thus 
`FileLogger` is doomed to write to the underlying file 
character-by-character in easily reproducible circumstances (e.g. 
log a range of characters); this issue probably doesn't affect 
the API though.


`Logger` has a bunch of public and documented `*Impl` functions...

Some other line comments I posted a while ago have not been 
addressed.


Re: @safety of Array

2014-10-13 Thread Jakob Ovrum via Digitalmars-d
On Monday, 13 October 2014 at 00:42:09 UTC, Brad Roberts via 
Digitalmars-d wrote:
I know it's a tricky implementation, but let's focus on the 
goal.. should Array be usable in @safe code?


Looks like the `RefCounted` dependency has to be made @safe first.


Re: @safety of Array

2014-10-14 Thread Jakob Ovrum via Digitalmars-d
On Tuesday, 14 October 2014 at 01:47:10 UTC, Brad Roberts via 
Digitalmars-d wrote:
That's why I asked the question I did.  The core question isn't 
about what the current implementation is or does but about 
where it should end up.  Should Array be usable in @safe code.


Well, I think it goes without saying that every piece of 
interface that is memory safe should be @safe. Granted, for 
abstract interfaces, like the range and container concepts, or 
virtual functions in classes and `interface`'s, some care is 
needed to determine whether or not memory safety should be a 
requirement, but for concrete implementations like `Array` we 
should provide the strongest guarantees possible.


To elaborate on my thinking for my previous reply: I don't know 
if Array's interface in its entirety is memory safe (element 
access looks murky, as was pointed out), but construction is 
definitely a memory safe part of it; so yes, I think there's work 
to be done here, and to that end, the safety of `RefCounted` has 
to be considered first. My initial thoughts are that at least 
construction of `RefCounted` should also be memory safe.


@safe vs @trusted is a red herring, it's just a matter of whether 
memory safety is automatically or manually checked.


(That said, the trap here is to disregard @safe because of 
current implementation deficits and just *assume* memory safety 
without proper checking and applying @trusted everywhere as a 
stop-gap measure. Just because it's clear that the interface is 
SafeD doesn't mean the implementation is (yet), and this is what 
minimized @trusted helps figure out. For example - although I'm 
not sure if it technically violates SafeD - if malloc signals OOM 
in Array.this, the code will steam ahead and try to emplace 
elements at an offset from null. Just applying @trusted and 
moving on would not catch cases like this.)


I don't think it's true that @safe is an afterthought for new 
code. New generic code uses @safe unit tests to test 
safe-readiness, and new non-generic code without regard for 
attributes is also pointed out in review. The problem with 
attributes is overwhelmingly with old code, not new code.


Re: std.experimental.logger formal review round 3

2014-10-14 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 15 October 2014 at 02:54:27 UTC, Dicebot wrote:
As there was quite some last moment feedback I am giving some 
more time for me to research issues a bit and Robert to address 
them :)


The Pareto Principle could be worth mentioning here. We were 80% 
of the way to a quality interface a long time ago, but the last 
20% is taking a disproportionate amount of time to iron out. I 
think all this criticism is indicative that we're holding this 
module to a high standard rather than the code being bad, which I 
think is a very good thing. Thankfully Marco stepped up and 
provided a solution to the threading problem, so I don't think 
it's that far off.


Apropos threading though, I'm not sure how to consolidate the 
fact that we're using shared memory without using `shared`. It 
seems like a failure to have such an intricately designed memory 
model, then as soon as we do threading in Phobos, we ignore it.


I still intend to go through all the documentation and fix things 
I can spot as soon as the interface is finalized.


Re: std.experimental.logger formal review round 3

2014-10-15 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 15 October 2014 at 09:25:07 UTC, Robert burner 
Schadek wrote:

On Wednesday, 15 October 2014 at 02:54:27 UTC, Dicebot wrote:
As there was quite some last moment feedback I am giving some 
more time for me to research issues a bit and Robert to 
address them :)


No need, I fixed the MultiLogger last weekend.


Fixed by simply removing the attempt at logarithmic time 
operations, and still not conforming to the Phobos container 
interface...


Re: Blaming the D language

2014-10-22 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 22 October 2014 at 06:42:06 UTC, Ali Çehreli wrote:

On 10/21/2014 11:06 PM, thedeemon wrote:


A[B] freshCleanAA;
aa = freshCleanAA;

(where A[B] denotes the type of aa)
That's it!


Alternative:

A[B] aa;
aa = aa.init;

Ali


`aa.init` is just `null`, which illustrates the problem better:

int[string] aa = [foo: 42];
int[string] aaAlias = aa;
aa = null;
assert(foo !in aa); // Ostensibly cleared...
assert(aaAlias[foo] == 42); // Until aliasing is introduced.


Re: Blaming the D language

2014-10-24 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 22 October 2014 at 07:42:22 UTC, Jonathan M Davis 
via Digitalmars-d wrote:
Well, the reality of the matter is that you can't truly clear 
it safely,
though we could definitely get closer. The in operator gives 
pointer access to
the internals, and the byKey and byValue may do the same (not 
to mention,
opApply), and they could be in progress when you try and clear 
out the AA, so
if you cleared it out, all of those would still have to work 
(or maybe throw

an Error in the cases where iteration is going on).


This is already the case because of .remove(). Adding a clear 
method wouldn't introduce any *new* problems.


Re: toString refactor in druntime

2014-10-31 Thread Jakob Ovrum via Digitalmars-d
On Friday, 31 October 2014 at 19:09:28 UTC, H. S. Teoh via 
Digitalmars-d wrote:
Besides, the sink version basically allows encapsulation of an 
output
range -- instead of calling x.toString(outputRange) you just 
write:


x.toString((const(char)[] data) { outputRange.put(data); });


In recent compiler versions we can just write:

x.toString(data = outputRange.put(data));


Re: DIP67: Associative Ranges

2014-10-31 Thread Jakob Ovrum via Digitalmars-d

On Tuesday, 28 October 2014 at 22:44:32 UTC, Freddy wrote:

http://wiki.dlang.org/DIP67
Abstraction over the build-in associative array(one type of 
range

for containers and another type for dynamic generators).
Plese criticize.


Any examples of what this actually accomplishes? Maybe an example 
of an algorithm that can do something useful with these 
primitives? A rationale for why these are the chosen primitives?


As the proposed associative range isn't consumable like other 
ranges, this seems more like a specific kind of *container*, not 
a *range*; indeed the text of the DIP seems to conflate the 
concepts, but they are separate by necessity.


Note that opIndex and opBinaryRight are already container 
primitives (see std.container). There's also the additional 
relevant primitive `removeKey`. Beyond that though, associative 
containers could need some more fleshing out in the container 
concept.


As it is, I think this proposal suffers both from lack of 
substance and confusing terminology.


Re: DIP67: Associative Ranges

2014-10-31 Thread Jakob Ovrum via Digitalmars-d

On Saturday, 1 November 2014 at 00:04:18 UTC, Jakob Ovrum wrote:

... opIndex and opBinaryRight are already container ...


Correction: opBinaryRight!in


Re: toString refactor in druntime

2014-11-01 Thread Jakob Ovrum via Digitalmars-d
On Saturday, 1 November 2014 at 05:27:16 UTC, Jonathan Marler 
wrote:

No need for the extra function, just call:

x.toString((outputRange.put));


That doesn't work for a wide variety of possible cases, notably 
when `put` is a function template or when the code depends on 
std.range.put or some other UFCS `put` function. As such, it 
should be avoided in generic code, and then you might as well 
avoid it in general, lest your algorithm unnecessarily ends up 
breaking with output ranges you didn't test for after refactoring.


(Note that parantheses are not required in your example)


Re: std.experimental.logger formal review round 3

2014-11-01 Thread Jakob Ovrum via Digitalmars-d
On Saturday, 1 November 2014 at 17:35:37 UTC, David Nadlinger 
wrote:
There is still a critical issue with std.experimental.logger 
that would prevent it from being merged right now: The abuse of 
@trusted all over the code.


Thank you. I was afraid I'd have to harp on it for the fourth 
time...




Re: Keeping a dynamic sorted range

2014-11-07 Thread Jakob Ovrum via Digitalmars-d

On Friday, 7 November 2014 at 14:11:32 UTC, bearophile wrote:

(This is a partial repost from a recent D.learn thread.)

In Phobos we have SortedRange and assumeSorted, but I do find 
them not very good for a common enough use case.


The use case is to keep a sorted array, keep adding items to it 
(adding larger and larger items at the end. Or sometimes even 
inserting items in the middle. In both cases I keep the sorting 
invariant). And while I add items, I also now and then want to 
perform a binary search on the sorted range.


So sometimes I'd like to do something like this (but a 
SortedRange doesn't have append):


struct Foo { int x; }
SortedRange!(Foo[], q{ a.x  b.x }) data;
data ~= Foo(5);
immutable n = data.upperBound(Foo(2)).length;

Bye,
bearophile


Facing this same problem, a while ago I started work on a 
generic, higher-order container that provides insertion, deletion 
and search while keeping itself sorted:


https://gist.github.com/JakobOvrum/f1738d31bb7ba7a46581

The above is just a WIP; it's not complete. Of course, positional 
container primitives like `insertFront` and `insertBack` will not 
be supported.


The implementation is fairly messy due to the lack of traits for 
containers, as well as due to some deficiencies in `SortedRange`.


It's obviously useful for arrays, and it's kind of clever how it 
can merge lists efficiently, but I'm not sure if it's really 
worth all the effort; is it really useful to have something like 
this that aims to support such a wide range of underlying 
containers? Is it actually useful in real programs for anything 
but arrays? So, I stopped working on it...


Re: Building JSON until 2.067

2015-02-04 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 5 February 2015 at 06:18:07 UTC, BlackEdder wrote:

On Thursday, 5 February 2015 at 06:03:38 UTC, Jakob Ovrum wrote:
On Thursday, 5 February 2015 at 01:10:18 UTC, Andrei 
Alexandrescu wrote:

On 2/4/15 5:06 PM, Matt Kline wrote:
Is there a JSON library that most other people are using 
instead?


http://vibed.org has a good one. -- Andrei


http://code.dlang.org/packages/std_data_json


http://code.dlang.org/packages/painlessjson
http://code.dlang.org/packages/jsonizer


std.data.json is the vibe.d JSON library, usable without having 
to pull in all of vibe.d. It was not my intent to advertise it, 
but rather advertise the best way to use it.


Re: Special Type Challenge

2015-02-06 Thread Jakob Ovrum via Digitalmars-d
On Saturday, 7 February 2015 at 01:55:27 UTC, Jonathan Marler 
wrote:

  Byte b;

  b = 0;
  b = 1;
  b = 255;
  b = -256;

  b = 'a';
  b = cast(const char)'a';
  b = cast(immutable char)'a';
  b = cast(byte)1;
  b = cast(const byte)1;
  b = cast(immutable byte)1;
  b = cast(ubyte)1;
  b = cast(const ubyte)1;
  b = cast(immutable ubyte)1;


These are possible with opAssign (which should be accompanied 
with corresponding constructor(s)).



  Byte echo(Byte b)
  {
return b;
  }
  b = echo('a');
  b = echo(cast(const char)'a');
  b = echo(cast(immutable char)'a');
  b = echo(cast(byte)1);
  b = echo(cast(const byte)1);
  b = echo(cast(immutable byte)1);
  b = echo(cast(ubyte)1);
  b = echo(cast(const ubyte)1);
  b = echo(cast(immutable ubyte)1);

  Byte[] barr;

  barr = teststring;
  barr = [0,1,2,3];
}


These are not possible as D does not support implicit 
construction.


Re: RFC: std.json sucessor

2015-02-05 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 21 August 2014 at 22:35:18 UTC, Sönke Ludwig wrote:

...


Added to the review queue as a work in progress with relevant 
links:


http://wiki.dlang.org/Review_Queue


Re: Should std.algorithm.find demand a reference to range elements?

2015-02-05 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 5 February 2015 at 11:06:39 UTC, Jakob Ovrum wrote:
On Thursday, 5 February 2015 at 11:04:41 UTC, Daniel Murphy 
wrote:
Jakob Ovrum  wrote in message 
news:flxonctqqtzmtyint...@forum.dlang.org...


However, this would set a possibly disruptive precedent that 
range algorithms must no longer use foreach on aggregate 
types...


I think this precedent already exists thanks to the bad 
behavior of foreach over narrow strings.


Good point.

I'll file a PR for `find` in any case.


https://github.com/D-Programming-Language/phobos/pull/2964


Re: Compile time iota

2015-01-22 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 21 January 2015 at 18:26:11 UTC, H. S. Teoh via 
Digitalmars-d wrote:
On Wed, Jan 21, 2015 at 07:14:09PM +0100, zeljkog via 
Digitalmars-d wrote:


Maybe something like this can be added to Fobos:

template Iota(int start, int stop, int step = 1){
template tuple(T...){
alias tuple = T;
}
static if(start  stop)
alias Iota = tuple!(start, Iota!(start + step, stop, 
step));

else
alias Iota = tuple!();
}


This is actually already implemented as 
std.typecons.staticIota, but
it's currently undocumented and restricted to only Phobos code. 
I'm not
sure why it was decided not to make it public, but if you file 
an
enhancement request, the devs can look at it and decide if it's 
worth

making it public.


T


There was a PR to make `staticIota` public, but it was superceded 
by a more general `toTypeTuple`[1] that works with any CTFE-able 
range, including the titular `iota`. It too was eventually 
closed, this time because of the whole naming situation. It's an 
unfortunate situation, but now that we've come this far, I think 
the way forward is to go ahead and try to get the std.meta rename 
merged.


[1] https://github.com/D-Programming-Language/phobos/pull/1472


Re: forcing @nogc on class destructors

2015-01-22 Thread Jakob Ovrum via Digitalmars-d
On Tuesday, 20 January 2015 at 18:12:27 UTC, ketmar via 
Digitalmars-d wrote:

Hello.

as there is no possibility to doing GC allocations in class
destructors, wouldn't it be nice to just force @nogc 
attribute on

such dtors?


Classes don't have to be designed to be allocated on the GC heap. 
Class instances can be allocated on the stack, the C heap, or 
anywhere else.


i know, i know, this will break alot of code. i'm pretty sure 
that

this will break alot of INVALID code, which better be broken at
compile-time anyway.


There is potentially a plethora of valid code broken by such a 
change:


 * Classes designed to be used on the stack or other non-GC-heap 
memory locations.
 * Class destructors that never call a GC function, but @nogc was 
nevertheless not applied throughout the codebase, maybe because 
it was an old or poorly maintainable codebase.
 * Users using non-standard or modified GC implementations that 
don't have this restriction.
 * Classes in programs that have ripped out the GC to begin with, 
replacing `new` and other GC primitives with something else. This 
one is dubious, as from a language standpoint, `new` is 
exclusively intended for GC allocation.
 * Class destructors calling into functions that predictively 
have both an allocating and non-allocating path, thus cannot be 
@nogc but can be verified at the call-site to be @nogc. Arguably 
such functions are poorly designed and should be split into two 
layers.


let's see how this proposal will be rejected. will there be 
some sane
reasons, or only the good old song about broken code? make 
your bets!


D is a systems-programming language and should cater to a wide 
variety of use patterns, including users who wish to use classes 
in non-GC memory locations. Perhaps splitting class destructors 
into two separate concepts, a destructor and a finalizer, with 
the latter being @nogc, could be a more satisfactory solution. 
Alternatively, maybe we should anticipate a standard GC 
implementation (or one of several standard implementations, like 
Java and .NET do) that does not have this restriction.


Re: Attributes lost in TypeInfo, please advise

2015-02-12 Thread Jakob Ovrum via Digitalmars-d
On Thursday, 12 February 2015 at 12:59:39 UTC, Steven 
Schveighoffer wrote:
I think given the necessity of the above (which was not 
discussed or noticed in that bug report), we should add a way 
to call the true destructor properly in the compiler.


-Steve


I think these do the right thing with only marginal overhead:

---
void destructRecurse(S)(ref S s)
if (is(S == struct))
{
static if (__traits(hasMember, S, __dtor))
s.__dtor();

foreach_reverse (ref field; s.tupleof)
{
alias Field = typeof(field);
static if (is(Field == struct)  
hasElaborateDestructor!Field)

destructRecurse(field);
}
}

void postblitRecurse(S)(ref S s)
if (is(S == struct))
{
foreach (ref field; s.tupleof)
{
alias Field = typeof(field);
static if (is(Field == struct)  
hasElaborateCopyConstructor!Field)

postblitRecurse(field);
}

static if (__traits(hasMember, S, __postblit))
s.__postblit();
}
---
I notice now it is missing proper handling of fixed-length 
arrays: I'll add that. Anything else missing?


Efficiency-wise they should at least be a lot better than the 
status quo - two indirect calls. For absolutely optimal 
performance it relies on the inliner, but if it is demonstrated 
to be a problem compared to the compiler-generated solution, it 
could always generate optimal code with some hands-on string 
mixins :)


I am aware that std.traits is not available in object_.d - the 
hasElaborate* templates are fairly simple and easy to reimplement.


Re: 521 days, 22 hours, 7 minutes and 52 seconds...

2015-01-26 Thread Jakob Ovrum via Digitalmars-d

On Monday, 26 January 2015 at 18:19:18 UTC, H. S. Teoh wrote:
On Mon, Jan 26, 2015 at 10:09:45AM -0800, Andrei Alexandrescu 
via Digitalmars-d wrote:

...is what took to get std.experimental.logger in Phobos.

https://github.com/D-Programming-Language/phobos/pull/1500

A time to celebrate! Many thanks to Robert who carried it 
through a
long gestation, Dicebot for managing the review process, and 
everybody

who provided feedback, especially Martin Nowak for his ideas.

[...]

Certainly, this deserves celebration!

But OTOH, if *this* is what it takes to contribute a new module 
to
Phobos, then it's no wonder we have trouble finding 
contributors...
Most would give up before they even try. I think there's an 
imbalance
here between the quality of existing Phobos modules vs. the 
quality

expected of future Phobos modules.


To be quite frank, the code was initially quite bad. Design 
decisions aside, there were many errors like not using attributes 
correctly and having messy algorithms with exponential time 
complexity. This hasn't been the case with all Phobos proposals.


(Also, valid criticisms were sometimes forgotten for a long time, 
and there were sometimes several months between patches, but 
things like these are unavoidable in a volunteer environment.)



Whatever happened to incremental
refinement??  Do we really expect flawless perfection before 
merging to,

of all places, std.*experimental*?


T


The deal to include it into std.experimental was only introduced 
at the very end of the review process.


Re: How can I help with pull requests if I don't have the authority to merge?

2015-01-29 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 29 January 2015 at 19:46:03 UTC, Jakob Ovrum wrote:
Although the Github tags aren't always kept up to date, this 
link might be useful when looking for patches that need review:


https://github.com/D-Programming-Language/phobos/labels/needs%20review


Of course, ditto for the other D repositories.


Re: How can I help with pull requests if I don't have the authority to merge?

2015-01-29 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 29 January 2015 at 13:42:15 UTC, Atila Neves wrote:

After this thread:

http://forum.dlang.org/thread/hapxxhusoniimfxie...@forum.dlang.org

I had some time today and headed over to Github to see if I 
could help out. But I'm not sure what I can do if I don't have 
the power to approve PRs. I'm not asking for that power, I 
haven't earned it yet. I'm just asking what it is I can do to 
help, especially on PRs that already have comments from a bunch 
of people.


Although the Github tags aren't always kept up to date, this link 
might be useful when looking for patches that need review:


https://github.com/D-Programming-Language/phobos/labels/needs%20review

Should I add comments to the ones that don't? Work on my own 
PRs instead?


Well, the ones that don't have any review might benefit more from 
you looking over it, but people often miss things; the more 
review the merrier. Please comment whenever you feel you have 
something to add!


Equally for your own patches, if you feel you have something to 
add, whether a bug fix, documentation improvement or new 
functionality, please send a PR :)




Re: decodeReverse

2015-01-06 Thread Jakob Ovrum via Digitalmars-d

On Tuesday, 6 January 2015 at 06:43:13 UTC, HaraldZealot wrote:
For my particular project (it binds with something like finite 
state machine) I will write some counterpart of decode function 
from std.utf. Future function will decode string backward, 
return dchar and change index passed by reference.


Is it interesting for community that I code this feature in 
general way targeting in phobos for future?


For UTF, there's already std.utf.strideBack which does most of 
the work. I don't know why there is no std.utf.decodeBack - 
should be very simple to wrap over strideBack.


However, for grapheme clusters, there isn't yet a counterpart for 
std.uni.graphemeStride/decodeGrapheme, which notably affects 
std.uni.byGrapheme, which is currently not a bidirectional range. 
Any improvement would be much appreciated.


Re: RFC: std.*.concept convention

2015-02-11 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 11 February 2015 at 08:21:40 UTC, Rikki Cattermole 
wrote:
As long as the std.concept package get's good documentation, I 
think its a damn good idea!


In the spirit of type concepts as a federation of types, not a 
hierarchy of types, I think std.*.concept, such as 
std.range.concept, is more appropriate than an std.concept 
package.


It would be the intuitive go-to module for documenting the 
concept, including abstract information, which we've had a hard 
time working into the reference documentation so far. To wit, the 
documentation for std.range defers to Andrei's informit.com 
article on ranges.


Re: Proposal : aggregated dlang git repository

2015-02-11 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 11 February 2015 at 05:39:59 UTC, H. S. Teoh wrote:
Jakob Ovrum has just submitted a PR to make (the current 
version of)

RefCounted reject interfaces, since currently it doesn't do that
correctly (it refcounts the reference to the interface rather 
than the

target object).

Given this is the current situation, it would appear to me to 
make
RefCounted work with class objects, all we have to do would 
be to
specialize RefCounted for classes, use malloc to allocate the 
necessary
space (plus the refcount, of course), and emplace() the class 
object

onto that space. Right?

Of course, given that it has been ... oh, months? years? since
RefCounted issues have been addressed, I'm probably just 
kidding myself
that there are no major monkey wrenches in the works that would 
make the
above simplistic solution not work. And I'm not sure I really 
want to
know... Not until I have an actual use case for RefCounted in 
my own
code, anyway, since otherwise I wouldn't have any confidence 
that I was

making the right decisions in making any changes to it.


I also think it doesn't look like a big job, but I didn't see any 
current activity on the subject and my own immediate priorities 
are elsewhere, hence the simple one-line PR as a stop-gap measure.


Re: RFC: std.*.concept convention

2015-02-11 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 11 February 2015 at 08:54:41 UTC, Jonathan M Davis 
wrote:

We really haven't been using the
term concepts for anything in D, and instead have been heavily 
using the
term traits for what you're talking about - e.g. isInputRange 
is considered

to be a trait.


My opinion is the opposite. I've never seen anyone use the term 
traits, but I have seen the term concept.



In addition, we probably don't want to confuse them with
C++'s concepts. Much as they're similar, they're quite not the 
same thing.


The implementation differs in the details but the idea is exactly 
the same. Using the same term is helpful for people who are 
familiar with C++ concepts.


Re: RFC: std.*.concept convention

2015-02-11 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 11 February 2015 at 09:11:18 UTC, Jonathan M Davis 
wrote:
We have a whole module full of them - std.traits - so we're 
already using
that term in Phobos, whereas you won't find the term concepts 
in there
anywhere. And you seem to be looking for exactly the same thing 
except in
specific areas - ranges, containers, etc. - rather than having 
all them

sitting in std.traits.


There is a difference between a concept and a trait. A concept 
can be composed of multiple traits. In the context of a concept, 
these traits could be called primitives.


Saying that `isInputRange` is a trait is just clumsy. It's a 
checker template. You could rephrase it and say that it's a 
checker template for the input range trait; but it doesn't check 
for a single distinguishing quality[1], it checks if all of a 
number of traits are present. Querying whether or not a type has 
the input range trait is just plain linguistically awkward.


Using the term concept puts us in line with C++, the biggest - 
perhaps the only - competitor D has in the field of template 
metaprogramming, which surely aids learning. Indeed, even the 
Wikipedia article on C++ concepts[2] seems like a good resource 
for understanding the same idea we have in D.


[1] http://www.merriam-webster.com/dictionary/trait
[2] https://en.wikipedia.org/wiki/Concepts_%28C%2B%2B%29


RFC: std.*.concept convention

2015-02-11 Thread Jakob Ovrum via Digitalmars-d


Preface


I'd like to start by saying that this is a relatively low-impact 
enhancement in the short term, but should pay off in the long 
term. It also requires very little effort, so it is low-hanging 
fruit, although it requires some foresight to see the benefit.



Primer of type concepts for the uninitiated (skip if you know 
this stuff)



In D we have the idea of a type concept. Current notable concepts 
are the range concept and the container concept. The idea is that 
any type that satisfies the operations of a certain usage pattern 
can be said to satisfy a certain type concept, and thus be usable 
in algorithms that use a permutation of said usage pattern. The 
operations making up a type concept are called the primitives of 
the concept.


For example, for a type to satisfy the input range concept, the 
following usage pattern must compile:

---
R r;  // can define a range object
if (r.empty) {}   // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range of non-void 
type

---
The three required operations for the input range concept are the 
front, empty and popFront primitives. In addition there may be 
certain restrictions on runtime behaviour; for example, `front` 
should never be called on an empty range.


For convenient verification of a type satisfying a concept, we 
have concept checker templates such as isInputRange[1].



Suggestion


Lately there is a trend of splitting up modules into packages in 
Phobos. Notably, std.range and std.container have been split up 
into packages.


Currently all the range concept checkers are defined in a module 
std.range.primitives, bundled with the UFCS implementations of 
the range primitives for in-built slice types.


Containers do not (yet) have concept checkers, but I consider it 
likely we'll see them in the future, as we see more generic 
container algorithms as well as higher-order containers.


Additionally, Andrei has suggested a new type RefCountedSlice!T 
that presents the same dynamic array interface of T[], but with a 
reference-counted backend in lieu of the GC backend of T[]. It is 
conceivable that generic array algorithms may want to accept 
either type, and thus the dynamic slice concept is born.


Putting the complexity of the container concept aside; I think we 
should factor out the concept checkers from std.range.primitives 
and put them in std.range.concept and establish a convention of 
using modules named std.*.concept for concept checkers in the 
future. The consistency gained by such a convention makes type 
concepts easier to understand and commonly used module names 
easier to remember. If we do it now, there is no breakage, as the 
splitting of std.range has not yet been released: hence the 
otherwise clumsy timing of this suggestion.


It is very little work, but anticipating complaints of 
bike-shedding if I didn't explain myself, I decided to post here 
first. I'd like to get some feedback before I file a PR.


[1] http://dlang.org/phobos/std_range#isInputRange


Re: Const-correctness and uniqueness. Again.

2015-02-09 Thread Jakob Ovrum via Digitalmars-d

On Monday, 9 February 2015 at 11:37:23 UTC, Jakob Ovrum wrote:
std.array.join is strongly pure (with appropriate template 
arguments), so its return value is implicitly convertible to 
immutable.


Err, implicitly convertible to *mutable*. It goes both ways.


Re: Const-correctness and uniqueness. Again.

2015-02-09 Thread Jakob Ovrum via Digitalmars-d

On Monday, 9 February 2015 at 10:56:31 UTC, Dicebot wrote:

Consider this trivial snippet:

```D
import std.array : join;

void main()
{
auto s = join([ aaa, bbb, ccc ]);
pragma(msg, typeof(s));
}
```

It outputs string which stands for immutable buffer.


The following works as well:
---
void main()
{
import std.array : join;
import std.stdio : writeln;

char[] s = join([foo, bar]);
writeln(s); //foobar
}
---

std.array.join is strongly pure (with appropriate template 
arguments), so its return value is implicitly convertible to 
immutable.


Re: Testing package proposed for Phobos

2015-02-08 Thread Jakob Ovrum via Digitalmars-d

On Monday, 9 February 2015 at 01:41:33 UTC, Walter Bright wrote:

Anyone interested in taking up this flag?


Is this idea different from the one in 
std.internal.test.dummyrange?


Re: Const-correctness and uniqueness. Again.

2015-02-09 Thread Jakob Ovrum via Digitalmars-d

On Monday, 9 February 2015 at 11:38:23 UTC, Jakob Ovrum wrote:

On Monday, 9 February 2015 at 11:37:23 UTC, Jakob Ovrum wrote:
std.array.join is strongly pure (with appropriate template 
arguments), so its return value is implicitly convertible to 
immutable.


Err, implicitly convertible to *mutable*. It goes both ways.


Sorry, this is indeed nonsense, I take it back. It only goes one 
way.


Re: Attributes lost in TypeInfo, please advise

2015-02-11 Thread Jakob Ovrum via Digitalmars-d
On Thursday, 12 February 2015 at 04:18:06 UTC, Adam D. Ruppe 
wrote:
On Thursday, 12 February 2015 at 04:08:23 UTC, Jakob Ovrum 
wrote:
Is it possible to call the destructor or postblit constructor 
directly


yes, they are available as obj.__dtor() and obj.__postblit(); 
But...



and will they correctly destruct/copy recursively


No.


Thanks.

So you'd have to loop through all members in a custom destroy 
function and call them yourself. Then attribute inference 
should work.


I feared as much. I'll cook something up and send a PR for review.


Attributes lost in TypeInfo, please advise

2015-02-11 Thread Jakob Ovrum via Digitalmars-d

Consider the following:

---
struct S
{
~this() @safe {}
}

void foo() @safe
{
S s;
// OK
}

void bar() @safe
{
S s;
destroy(s);
// test.d(15): Error: safe function 'test.bar' cannot call 
system function 'object.destroy!(S).destroy'

}
---

`destroy` is used in algorithms using low-level operations like 
`emplace[Ref]`, and while `destroy` itself is a template and thus 
enjoys attribute inference, it calls the non-generic 
typeid(T).destroy function, which is unconditionally @system. 
This unsafety then propagates all the way up to high-level code 
that is otherwise inferred to be safe.


The `postblit` TypeInfo method, used from `emplace[Ref]`, has the 
same problem.


Is it possible to call the destructor or postblit constructor 
directly, and will they correctly destruct/copy recursively like 
TypeInfo.destroy/postblit do? If so, we should change `destroy` 
and `emplaceImpl` to use direct calls ASAP.


Re: Should std.algorithm.find demand a reference to range elements?

2015-02-05 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 5 February 2015 at 10:36:34 UTC, Eduardo Pinho wrote:
Some assistance on understanding what is wrong here is greatly 
appreciated.


There's definitely nothing wrong with your code.

I always thought foreach preferred opApply when available because 
internal iteration can in theory be faster than external 
iteration (although it rarely is with current compilers because 
the indirect call to the delegate is often the bottleneck), but 
as you've pointed out, the specification claims external 
iteration is be preferred. Either the specification has to be 
changed, or the compiler has to be changed.


If internal iteration remains preferred, `find` should probably 
be changed to use an explicit for-loop:

---
size_t i = 0;
for (auto h = haystack.save; !h.empty; h.popFront())
{
if (predFun(h.front))
return haystack[i .. $];
++i;
}
return haystack[$ .. $];
---
(`haystack` is known to be a forward range in this portion of the 
code)


However, this would set a possibly disruptive precedent that 
range algorithms must no longer use foreach on aggregate types...


Re: Should std.algorithm.find demand a reference to range elements?

2015-02-05 Thread Jakob Ovrum via Digitalmars-d

On Thursday, 5 February 2015 at 11:04:41 UTC, Daniel Murphy wrote:
Jakob Ovrum  wrote in message 
news:flxonctqqtzmtyint...@forum.dlang.org...


However, this would set a possibly disruptive precedent that 
range algorithms must no longer use foreach on aggregate 
types...


I think this precedent already exists thanks to the bad 
behavior of foreach over narrow strings.


Good point.

I'll file a PR for `find` in any case.


Re: Building JSON until 2.067

2015-02-04 Thread Jakob Ovrum via Digitalmars-d
On Thursday, 5 February 2015 at 01:10:18 UTC, Andrei Alexandrescu 
wrote:

On 2/4/15 5:06 PM, Matt Kline wrote:
Is there a JSON library that most other people are using 
instead?


http://vibed.org has a good one. -- Andrei


http://code.dlang.org/packages/std_data_json


Re: From the cycle Topic of the day - .gitignore: how big is too big?

2015-03-21 Thread Jakob Ovrum via Digitalmars-d
On Sunday, 22 March 2015 at 01:15:07 UTC, Andrei Alexandrescu 
wrote:
I've left a comment recently at 
https://github.com/D-Programming-Language/phobos/pull/3087.


So what's the deal with that? Whenever a new tool leaves some 
trash, do we chalk a circle on the pavement around it?



Andrei


Aye, our tools should be configured to put temporary files and 
output files in uniform directories that can be .gitignore'd 
wholesale. The problem is not in .gitignore but our makefiles.


Re: What is going on here?

2015-03-04 Thread Jakob Ovrum via Digitalmars-d

On Wednesday, 4 March 2015 at 20:37:20 UTC, Marc Schütz wrote:

On Wednesday, 4 March 2015 at 19:36:20 UTC, Ali Çehreli wrote:

On 03/04/2015 07:43 AM, Steven Schveighoffer wrote:
I believe destructors are not run when you throw inside a 
constructor.

So plan to deallocate if the ctor throws:

a = A(var + 1);
scope(failure) destroy(a);

-Steve


I don't want that. :)



Then vote here :-P
https://issues.dlang.org/show_bug.cgi?id=14246


Added my vote. The construction heuristic needs to become more 
sophisticated and well-defined anyway.


Re: Making RCSlice and DIP74 work with const and immutable

2015-03-01 Thread Jakob Ovrum via Digitalmars-d
On Sunday, 1 March 2015 at 01:40:40 UTC, Andrei Alexandrescu 
wrote:
We have a few candidates for solutions, but wanted to open with 
a good discussion first. So, how do you envision a way to 
define and access mutable metadata for objects (including 
immutable ones)?



Andrei


I don't think const or immutable intrusive-reference-counted 
classes is a feasible idea.


I understand the motivation: we want to dynamically allocate a 
class instance, initialize it and never mutate it again, and pass 
it around freely; *without* using tracing GC. Having it typed as 
immutable helps code readability and whatnot.


However, AFAICS, it comes with a serious problem. Immutable 
objects are freely passable between threads, so surely an 
immutable RC object would need atomic counting just like a shared 
RC object, but unlike shared, immutable does not necessarily 
express the intent of sharing between threads; the immutable RC 
object could easily be counting atomically for nothing.


There might be other problems, such as problems regarding ROM.

This is not a problem with reference-counting as a whole but with 
intrusive reference-counting. With RefCounted, 
immutable(RefCounted!T) makes no sense, but RefCounted!(immutable 
T) does. It's also neatly composable; 
shared(RefCounted!(immutable T)) makes sense too.


I wish we had external, composable reference-counting for class 
instances. I know why that's problematic, so sorry for posting 
without any suggestion on how to proceed...


Re: Making RCSlice and DIP74 work with const and immutable

2015-03-01 Thread Jakob Ovrum via Digitalmars-d

On Sunday, 1 March 2015 at 15:40:06 UTC, Atila Neves wrote:
I've lost count now of how many times I've had to downgrade to 
auto despite always wanting immutable or const. This doesn't 
work:


 auto reg = regex(`(foo)`);
 const match = foo.matchAll(reg);
 writeln(match.captures); //oops, captures isn't const

It should, but it doesn't. Maxime talked about it here as well:

http://pointersgonewild.com/2014/07/11/the-constness-problem/

Atila


`match.captures` is a range; it's only natural for a range to 
have mutable state to be iterable.


D's const is a bridge between immutable and mutable. const has to 
be transitive because immutable is transitive. Don't use it as if 
it was C++ const: there's no logical const in D, and if there 
ever will be, it can't use the same `const` type qualifier.


Re: Mac Apps That Use Garbage Collection Must Move to ARC

2015-02-23 Thread Jakob Ovrum via Digitalmars-d

On Monday, 23 February 2015 at 01:38:35 UTC, Manu wrote:

On 23 February 2015 at 07:47, Walter Bright via Digitalmars-d
digitalmars-d@puremagic.com wrote:

On 2/22/2015 8:36 AM, Manu via Digitalmars-d wrote:


I have no idea where to start.



Start by making a ref counted type and see what the pain 
points are.


All my ref counting types fiddle with the ref in every 
assignment, or
every function call and return. Unless the language has some 
sort of
support for ref counting, I don't know how we can do anything 
about

that.


There's no move constructor in D, so how did you manage that?


Re: Mac Apps That Use Garbage Collection Must Move to ARC

2015-02-22 Thread Jakob Ovrum via Digitalmars-d

On Sunday, 22 February 2015 at 00:43:47 UTC, Manu wrote:
D's GC is terrible, and after 6 years hanging out in this 
place, I

have seen precisely zero development on the GC front.


You must have missed RTInfo, Rainer's precise heap scanner and 
Sociomantic's concurrent GC.


  1   2   3   >