Re: Copying parameter lists verbatim
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
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
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`
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`
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
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
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
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
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
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
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`
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?
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?
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?
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
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
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
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
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
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
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
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
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?
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?
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?
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?
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?
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?
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.
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
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.
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.
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
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
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
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
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
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.
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
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?
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
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
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
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
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
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
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
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
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?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?
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
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
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
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...
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?
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?
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
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
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
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
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
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
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.
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.
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
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.
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
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
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?
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?
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
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?
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?
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
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
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
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
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.