Re: [GSOC] New unicode module beta, with Grapheme support!
On 23-Aug-12 10:34, Jacob Carlborg wrote: On 2012-08-22 23:31, Dmitry Olshansky wrote: Well, officially the final bell has rung, marking the end of GSOC. Cool. P.P.S. Volunteers who'd like to test x64 are welcome to run rdmd gen_uni.d and report back (maybe it's my local setup problem). On Mac OS X, using DMD 2.060 64bit, the assert at line 568 is triggered. The last part of the output is: Great... at least the error is the same :) So the only Q remains is why Phobos tests fail for me but doh. Guess I'll have to go the old painful way of debugging. 2FA1D ---> 2A600 2fa1d -~-> 2a600 core.exception.AssertError@gen_uni(568): Assertion failure 5 gen_uni 0x0001000a06ea _d_assertm + 38 6 gen_uni 0x000113f7 void gen_uni.__assert(int) + 23 7 gen_uni 0x0001377c void gen_uni.writeTries().int __foreachbody8149(ref dchar, ref ushort) + 124 8 gen_uni 0x00010009f406 _aaApply2 + 106 9 gen_uni 0x00013497 void gen_uni.writeTries() + 687 10 gen_uni 0x000113b7 _Dmain + 1131 11 gen_uni 0x0001000a108a extern (C) int rt.dmain2.main(int, char**).void runMain() + 34 12 gen_uni 0x0001000a0a41 extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate()) + 45 13 gen_uni 0x0001000a10d4 extern (C) int rt.dmain2.main(int, char**).void runAll() + 56 14 gen_uni 0x0001000a0a41 extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate()) + 45 15 gen_uni 0x0001000a09cb main + 235 16 gen_uni 0x00010f44 start + 52 17 ??? 0x0001 0x0 + 1 I also piped it to a file which resulted in this: http://pastebin.com/xjg68CdG -- Olshansky Dmitry
Re: Fragile ABI
On Tuesday, 21 August 2012 at 15:15:02 UTC, David Piepgrass wrote: Finally, it's Windows-only (although it has been reimplemented on Linux, e.g. for WINE) and modules must be registered in the Windows Registry. Conceptually COM is just a set of ideas for interoperable component design, which happens to actually work across languages and frameworks: .net, C, C++, Delphi, D. Registry works only as a centralized repository of components which is needed if you want to plug arbitrary components into your system, it has nothing to do with the problem of fragile ABI.
Re: Ascii matters
Sean Kelly: Gotcha. Despite it being something I'd use regularly, I wouldn't want this in Phobos because it seems like it could cause maintenance problems. I'd rather explicitly cast to ubyte as a way to flag that I was doing something potentially unsafe. What's unsafe in what I have presented? The constructor verifies every char to be in 7 bits, and then you use the new type safely. No casts, and no need to flag something as unsafe. This usage of types to denote capabilities is quite common in functional languages, see articles I've recently linked here as: http://tomasp.net/blog/type-first-development.aspx Bye, bearophile
Formatted read consumes input
As title implies: import std.stdio; import std.format; void main() { string s = "42"; int v; formattedRead(s, "%d", &v); writefln("[%s] [%s]", s, v); } [] [42] Is this the "expected" behavior? Furthermore, it is not possible to try to "save" s: import std.stdio; import std.format; import std.range; void main() { string s = "42"; int v; formattedRead(s.save, "%d", &v); writefln("[%s] [%s]", s, v); } main.d(9): Error: template std.format.formattedRead does not match any function template declaration C:\D\dmd.2.060\dmd2\windows\bin\..\..\src\phobos\std\format.d(526): Error: template std.format.formattedRead(R,Char,S...) cannot deduce template function from argument types !()(string,string,int*) The workaround is to have a named backup: auto ss = s.save; formattedRead(ss, "%d", &v); I've traced the root issue to formattedRead's signature, which is: uint formattedRead(R, Char, S...)(ref R r, const(Char)[] fmt, S args); Is there a particular reason for this pass by ref? It is inconsistent with the rest of phobos, or even C's scanf? Is this a file-able bug_report/enhancement_request?
Re: Ascii matters
On 23/08/12 05:05, bearophile wrote: Sean Kelly: I'm clearly missing something. ASCII and UTF-8 are compatible. What's stopping you from just processing these as if they were UTF-8 strings? std.algorithm is not closed (http://en.wikipedia.org/wiki/Closure_%28mathematics%29 ) on UTF-8, its operations lead to UTF-32. Which operations in std.algorithm over map 0-0x7F into higher characters?
Non-virtual private struct inheritance
In C++, it is a very common practice, when writing a struct template, to have said template derive from a base non-template struct. This makes sure there is no executable bloat, and, more often than not, the inheritance is private, so invisible to users (no "interface leak"). For instance, std::list is a classic example of this: First, you have the template create a node, and then you defer to the base class for all insertions/deletions, that don't really care about what a T is. My first question is: Is such an approach even encouraged in D? Or is the module compilation system able to see through what does/doesn't depend on these parameters? Can be swapping inheritance for member variables, or free standing external methods. Both works most of the time, but neither are quite as polyvalent. ... D being a heavily templated system language, executable size is something that should be controlable, correct? Is there any chance we could see this kind of limited inheritance for structs? As in just basic non-polymorphous inheritance? I seem to remember a few threads about other users wishing for inheritance with structs...
Re: Ascii matters
Don Clugston: Which operations in std.algorithm over map 0-0x7F into higher characters? The first example I've shown: string s = "test string"; dchar[] s2 = map!(x => x)(s).array(); // Uses the Id function Bye, bearophile
Re: Non-virtual private struct inheritance
monarch_dodra: In C++, it is a very common practice, when writing a struct template, to have said template derive from a base non-template struct. This makes sure there is no executable bloat, "alias this" seems to help both for composition and against template bloat: struct Foo { int x; int bar() { return x * 2; } } struct Bar(T) { Foo f; T y; alias f this; } void main() { Bar!int b1; b1.x = 10; assert(b1.bar() == 20); Bar!double b2; b2.x = 100; assert(b2.bar() == 200); } In the asm listing there is only one bar: _D3foo3Foo3barMFZi: enter 4, 0 mov EAX, [EAX] add EAX, EAX leave ret Another way to fight template bloat is the @templated() I have suggested elsewhere, that applied to something inside a template allows you to choose what that something is templated to (even nothing). Bye, bearophile
Re: Non-virtual private struct inheritance
On Thursday, 23 August 2012 at 13:17:23 UTC, bearophile wrote: monarch_dodra: In C++, it is a very common practice, when writing a struct template, to have said template derive from a base non-template struct. This makes sure there is no executable bloat, "alias this" seems to help both for composition and against template bloat: struct Foo { int x; int bar() { return x * 2; } } struct Bar(T) { Foo f; T y; alias f this; } void main() { Bar!int b1; b1.x = 10; assert(b1.bar() == 20); Bar!double b2; b2.x = 100; assert(b2.bar() == 200); } In the asm listing there is only one bar: _D3foo3Foo3barMFZi: enter 4, 0 mov EAX, [EAX] add EAX, EAX leave ret Another way to fight template bloat is the @templated() I have suggested elsewhere, that applied to something inside a template allows you to choose what that something is templated to (even nothing). Bye, bearophile Thanks for the answer. Very nice. "alias this" is still the first thing I think about, but in this case, it works perfectly well actually.
Re: Ascii matters
On Aug 23, 2012, at 4:25 AM, bearophile wrote: > Sean Kelly: > >> Gotcha. Despite it being something I'd use regularly, I wouldn't want this >> in Phobos because it seems like it could cause maintenance problems. I'd >> rather explicitly cast to ubyte as a way to flag that I was doing something >> potentially unsafe. > > What's unsafe in what I have presented? The constructor verifies every char > to be in 7 bits, and then you use the new type safely. No casts, and no need > to flag something as unsafe. > > This usage of types to denote capabilities is quite common in functional > languages, see articles I've recently linked here as: > http://tomasp.net/blog/type-first-development.aspx So it throws an exception if there are non-ASCII characters in the range? Is this really better than just casting the input array to ubyte?
Re: Ascii matters
Sean Kelly: So it throws an exception if there are non-ASCII characters in the range? Is this really better than just casting the input array to ubyte? The cast to ubute[] doesn't perform a run-time test of the validity of the input, so yeah, the exception is better. Your code is also able to catch and manage the exception (like asking the user for another valid input file). If you carry around some type as "Astring", later you don't have to cast it back to char[] to print the data as a string (this discussion is about data that is naturally text, this discussion is not about generic numerical octets). An appropriate type statically encodes in your program that you are using an ascii string. This makes your code more readable. But when in the code you see a variable of generic type ubyte[] it doesn't tell you a lot about its contents. Bye, bearophile
Re: Vote for the new std.hash (oops, std.digest)
Dmitry Olshansky wrote: > The discussion around new unified API for digest hash functions has > subdued, just in time as the review period has ended. > > The voting for std.digest package starts today and ends on 29 > August. > > Rules are simple: reply in this thread with definite "YES" or "NO" > on whether this package should go into Phobos. Including descriptive > short notes is appreciated (esp. the NO ones). > > > Latest locations of docs and source: > > Code: (location changed!) > https://github.com/jpf91/phobos/tree/newHash/std/digest > https://github.com/jpf91/phobos/compare/master...newHash > > Docs: (location changed!) > http://dl.dropbox.com/u/24218791/d/phobos/std_digest_digest.html > http://dl.dropbox.com/u/24218791/d/phobos/std_digest_md.html > http://dl.dropbox.com/u/24218791/d/phobos/std_digest_sha.html > http://dl.dropbox.com/u/24218791/d/phobos/std_digest_crc.html > YES. I like it. The API is solid and future-proof for more digesting. Many thanks Johannes. Jens
Re: Vote for the new std.hash (oops, std.digest)
On Wednesday, 22 August 2012 at 12:36:08 UTC, Dmitry Olshansky wrote: The discussion around new unified API for digest hash functions has subdued, just in time as the review period has ended. The voting for std.digest package starts today and ends on 29 August. Rules are simple: reply in this thread with definite "YES" or "NO" on whether this package should go into Phobos. Including descriptive short notes is appreciated (esp. the NO ones). Latest locations of docs and source: Code: (location changed!) https://github.com/jpf91/phobos/tree/newHash/std/digest https://github.com/jpf91/phobos/compare/master...newHash Docs: (location changed!) http://dl.dropbox.com/u/24218791/d/phobos/std_digest_digest.html http://dl.dropbox.com/u/24218791/d/phobos/std_digest_md.html http://dl.dropbox.com/u/24218791/d/phobos/std_digest_sha.html http://dl.dropbox.com/u/24218791/d/phobos/std_digest_crc.html Can all the algorithms work at compile time (given immutable constant data, e.g. a string) ? YES : NO. Hope that's descriptive.
Re: Null references
On 21/08/2012 21:17, Nick Treleaven wrote: I have an Option struct on my home computer that only allows access to the held value if the error case is simultaneously handled: Option!int a = foo(); int n = a.match!( (int x) => x, (None n) => 0 // or throw, or what have you. ); I've now implemented match, similar to the above: https://github.com/ntrel/d-maybe/blob/master/maybe.d#L222 My match() always returns Maybe!T, because for pointers the lambdas could return null. Taken from the unittest: assert(match!(to!string, ()=>"")(maybe(2)) == "2"); assert(match!(to!string, ()=>"")(Maybe!int()) == ""); assert(match!((x, y)=>text(x, y), {})(maybe(2), maybe(34)) == "234"); assert(match!((x, y)=>text(x, y), {})(Maybe!int(), maybe(34)) == null); assert(match!((x, y)=>text(x, y), ()=>"none")(Maybe!int(), maybe(34)) == "none"); I'd be interested to see your Option code. Nick
Re: standard ranges
Sorry to resurrect this thread, I've been very absent from D, and am just now going through all these old posts. On Wed, 27 Jun 2012 17:41:14 -0400, Timon Gehr wrote: On 06/27/2012 11:11 PM, Steven Schveighoffer wrote: No, druntime, and include minimal utf support. We do the same thing with AssociativeArray. In this case it is misleading to call it a library type. What I mean is, the compiler does not define the structure of it. It simply knows it exists, and expects a certain API for it. The type itself is purely defined in the library, and could possibly be used directly as a library type. If you want immutable(char)[], use "abc".codeunits or equivalent. I really don't want to type .codeunits, but I want to use immutable(char)[] everywhere. This 'library type' is just an interface change that makes writing nice and efficient code a kludge. When most string functions take strings, why would you want to use immutable(char)[] everywhere? Because the proposed 'string' interface is inconvenient to use and useless. It is a struct with one data member and no additionally maintained invariant, and it strictly narrows the essential parts of the interface to the data that is reachable without a large typing overhead. immutable(char)[] supports exactly the operations I usually need. Maybe I'm not representative. Most usages of strings are to concatenate them, print them, use them as keys, read them from a stream, etc. None of this requires direct access to the data. They can be treated as a nebulous type. So maybe you are in the minority. I don't really know. The current situation is not simple to understand. It is simple, even if not immediately obvious. It does not have to be immediately obvious without explanation. It needs to be convenient. I will respond to this in a different way. This is the confusing part: string x; assert(!hasLength!string); assert(!isRandomAccessRange!string); auto len = x.length; auto c = x[0]; // wtf? It is *always* going to cause people to question isRandomAccessRange and hasLength because clearly a string has the purported properties needed to satisfy both. Generic code that accepts arrays has to special-case narrow-width strings if you plan to use phobos with them in some cases. That is a horrible situation. Generic code accepts ranges, not arrays. All necessary (or maybe unnecessary, I don't know) special casing is already done for you in Phobos. The _only_ thing that is problematic is the inconsistent 'foreach' behaviour. Plenty of generic code specializes on arrays. Ok, point taken. But plenty of generic code then specializes on strings as well. Would the net gain be so huge? There is also always the option of just not passing strings to some helper template function you defined. The net gain is not in the reduction of specializations -- of course we will need specializations for strings because to do any less would make D extremely inefficient compared to other languages. The gain is in the reduction of confusion. We are asking our users "I know, I know, it's an array, but *please* pretend it's not! Don't listen to the compiler!" And this is for a *BASIC* type of the language! range.save() is the same thing. It prevents nothing, and you have to take special care to avoid using basic operations (i.e. assign) and pretend they don't exist, even though they compile. To me, that is worthless. If a string does not support random access, then str[0] should not compile. period. You are right about the random-access part, but the definition of an array does not depend on the 'range' concept. The range concept is notably more confusing with strings that are random access types but not random access ranges, even though they support all the properties needed for a random access range. -Steve
Re: Vote for the new std.hash (oops, std.digest)
On Wednesday, 22 August 2012 at 12:36:08 UTC, Dmitry Olshansky wrote: The discussion around new unified API for digest hash functions has subdued, just in time as the review period has ended. Yes.
Re: Null references
Is there any special reason why these functions doesn't get "Maybe" as (const) ref? void show(T)(Maybe!T m) bool opEquals(Maybe!T m) void opAssign(Maybe!T m)
Re: Direct access to struct construction, copying and destruction
On Wed, 11 Jul 2012 04:21:29 -0400, Benjamin Thaut wrote: I already now what type info does, it does nothing. The compiler fills in the xpostblit and xdtor fields of the TypeInfo_Struct with the correct function pointers to postblit or destruct functions. These fields always contain the correct function to call. But the __postblit and __dtor funtions that are directly callable on the struct itself, are only correct if there is a explicit destructor / postblit constructor defined. So it shouldn't be much of a problem to also expose the __fielddtor and __fieldpostblit functions that get filled into the TypeInfo_Struct object anyway. Also see this: http://d.puremagic.com/issues/show_bug.cgi?id=5667 -Steve
Re: More on vectorized comparisons
On 8/22/2012 7:19 PM, bearophile wrote: Some time ago I have suggested to add support to vector comparisons in D, because this is sometimes useful and in the modern SIMD units there is hardware support for such operations: I think that code is semantically equivalent to: void main() { double[] a = [1.0, 1.0, -1.0, 1.0, 0.0, -1.0]; double[] b = [10, 20, 30, 40, 50, 60]; double[] c = [1, 2,3, 4, 5,6]; foreach (i; 0 .. a.length) if (a[i] > 0) b[i] += c[i]; } After that code b is: [11, 22, 30, 44, 50, 60] This means the contents of the 'then' branch of the vectorized comparison is done only on items of b and c where the comparison has given true. This looks useful. Is it possible to implement this in D, and do you like it? Well, right now the binary operators == != >= <= > and < are required to return bool instead of allowing a user defined type, which prevents a lot of the sugar you would want to make the code nice to write. Without the sugar the code would ends up this: foreach(i; 0 .. a.length) { float4 mask = greaterThan(a[i], float4(0,0,0,0)); b[i] = select(mask, b[i] + c[i], b[i]); } in GPU shader land this expression is at least simpler to write: foreach(i; 0 .. a.length) { b[i] = (b[i] > 0) ? (b[i] + c[i]) : b[i]; } All of these implementations are equivalent and remove the branch from the code flow, which is pretty nice for the CPU pipeline. In SIMD the comparisons generate masks into a register which you can immediately use. On modern (SSE4) CPUs the select is a single instruction, on older ones it takes three: (mask & A) | (~mask & B), but its all better than a real branch. If you have a large amount of code needing a branch, you can take the mask generated by the compare, and extract it into a CPU register, and compare it for 0, nonzero, specific or any bits set. a float4 comparison ends up generating 4 bits, so the code with a real branch is like: if (any(a[i] > 0)) { // do stuff if any of a[i] are greater than zero } if (all(a[i] > 0)) { // do stuff if all of a[i] are greater than zero } if ((getMask(a[i] > 0) & 0x7) == 0x7) { // do stuff if the first three elements are greater than zero }
Re: profiler issues: time overflows, conversion to seconds, gui/html output
On 23.08.2012 05:52, timotheecour wrote: I'm not sure how to interpret trace.log from running dmd with -profile (on osx at least). I inserted a stopwatch inside main, which gave 35.8 seconds. 1) How to convert times in trace.log to seconds? Eg, how to get 35.8 seconds using the numbers below? here's the first last line for times: Timer Is 3579545 Ticks/Sec, Times are in Microsecs Num TreeFuncPer CallsTimeTimeCall here's the last line: 1 16317420002 -43499161 -43499161 _Dmain The trace code is in druntime/rt/trace.d. There you can see that the ticks/sec is just set to the shown constant value for anything but Windows, but RDTSC is used to read the processor cycles. So the values are probably off by a factor of 300 to 1000. 2) Why are there negative numbers? (seems like an overflow problem, but the total time is quite small so it seems the scale is wrong). The time in ms is calculated as (time * 100) / freq, so with a processor speed of 2GHz, this will overflow after about 2000s. This doesn't seem to explain negative values in your run, so some random hints: - if you rerun the program, results will accumulate in trace.log - if you are calling recursive functions from inside main, there might be some issues with the timings of these functions (from my own experience from writing a profiler, it can get quite tricky to measure the execution time of recursive functions), and these are used to calculate the FuncTime of main. 3) are there any tools to visualize trace.log (eg gui, html or otherwise)? The only ones I found were outdated (ptrace.d for tango and profiled.d for D1) Visual D lets you explore trace.log in a browse window inside Visual Studio, but I guess this won't help you on OSX.
Re: Null references
On Thu, 23 Aug 2012 18:27:41 +0200, Nick Treleaven wrote: I'd be interested to see your Option code. Here you go. After looking at your code, and with Modern C++ Design fresh in mind, I see that match and hasValue might have worked better as free functions. I took the liberty of implementing the optional function calls discussed earlier. If your eyes glaze over or you feel an urge to kill, you are likely looking at that part of the code. -- Simen Option.d Description: Binary data
Re: Vote for the new std.hash (oops, std.digest)
d_follower wrote: > On Wednesday, 22 August 2012 at 12:36:08 UTC, Dmitry Olshansky > wrote: > >The discussion around new unified API for digest hash functions > >has subdued, just in time as the review period has ended. > > > >The voting for std.digest package starts today and ends on 29 > >August. > > > >Rules are simple: reply in this thread with definite "YES" or "NO" > >on whether this package should go into Phobos. Including > >descriptive short notes is appreciated (esp. the NO ones). > > > > > >Latest locations of docs and source: > > > >Code: (location changed!) > >https://github.com/jpf91/phobos/tree/newHash/std/digest > >https://github.com/jpf91/phobos/compare/master...newHash > > > >Docs: (location changed!) > >http://dl.dropbox.com/u/24218791/d/phobos/std_digest_digest.html > >http://dl.dropbox.com/u/24218791/d/phobos/std_digest_md.html > >http://dl.dropbox.com/u/24218791/d/phobos/std_digest_sha.html > >http://dl.dropbox.com/u/24218791/d/phobos/std_digest_crc.html > > Can all the algorithms work at compile time (given immutable > constant data, e.g. a string) ? YES : NO. It says "Digests do not work in CTFE". Just checked it for MD5. I do not know but I think this is just a current limitation of the CTFE implementation. Jens
Re: More on vectorized comparisons
Sean Cavanaugh: Well, right now the binary operators == != >= <= > and < are required to return bool instead of allowing a user defined type, which prevents a lot of the sugar you would want to make the code nice to write. The hypothetical D sugar I was looking for is this, where 'a', 'b' and 'c' are normal dynamic arrays of doubles (not of float[4] of double[2]) (currently this code is a syntax error): if (a[] > 0) b[] += c[]; The front-end is able to implement those two lines of code as it likes, like seeing those normal arrays as arrays of double[2] (or double[4] on more modern CPUs) and put there all the needed intrinsics or assembly needed to implement that semantics. So what's the problem the > operator causes in this code? Bye, bearophile
Re: Dynamic loading, D all the way (dmd 64bit 2.060/Ubuntu 64bit 12.04/x86_64)
On Wednesday, 22 August 2012 at 16:57:26 UTC, Paulo Pinto wrote: On Wednesday, 22 August 2012 at 15:51:05 UTC, Philip Daniels wrote: snip< If we had dynamic loading, would we be able to do dependency injection in D? Dependency injection does not require dynamic loading per se. It is all about using interfaces instead of classes, and initializing the corresponding instance members. You just need some piece of code that takes the responsibility of locating such interfaces, by registering the classes somehow, or by compile time reflection, which gets called on program initialization. You can do this in D today. -- Paulo But wouldn't that require you to link everything together at, err, compile time? What I'm getting at is, would it be possible to port a DI/IoC tool such as StructureMap (http://docs.structuremap.net/index.html) or Spring to D? This can handle tasks such as creating dynamic plug-in architectures. For example, given SomeBigApp.exe (not written by me) which looks in standard folders for components implementing a particular interface, I can just drop my code in that folder and have it loaded at runtime. I could even drop it in there after the program starts running. I know how to achieve this in the .Net world, just wondered if it was possible in D.
Re: Vote for the new std.hash (oops, std.digest)
Yes. The API seems fairly solid to me, and the need for these things is fairly wide reaching.
Phobos unittest failure on single-core machines
When trying to run the phobos unittests on my 32- and 64-bit linux single-processor machines, I get this output: Testing generated/linux/debug/64/unittest/std/parallelism totalCPUs = 1 core.exception.AssertError@std.parallelism(4082): unittest failure Has anyone else seen this, or is possible that I have an error in my dmd setup? (I'm using dmd/druntime/phobos from git HEAD, building in what I thought was the normal manner). --Ed McCardell
Consistency, Templates, Constructors, and D3
DISCLAIMER: This isn't a feature request or anything like that. It's ONLY intended to stir _constructive_ conversation and criticism of D's existing features, and how to improve them _in the future_ (note the 'D3' in the title). I've had a couple of ideas recently about the importance of consistency in a language design, and how a few languages I highly respect (D, C#, and Nimrod) approach these issues. This post is mostly me wanting to reach out to a community that enjoys discussing such issues, in an effort to correct any mis-conceptions I might hold, and to spread potentially good ideas to the community in hopes that my favorite language will benefit from our discussion. --- First, let me assert that "Consistency" in a language is critically important for a few reasons: 1. One way of doing things means one way to _remember_ things. It keeps us sane, focused, and productive. The more we have to fight the language, the harder it is to master. 2. Less things to remember means it's easier to learn. First impressions are key for popularity. 3. Less discrepancies means fewer human errors, and thus, fewer "stupid" bugs. # CAST/TRAITS ## To start, let's look at: cast(T) vs to!T(t) In D, we have one way to use template function, and then we have special keyword syntax which doesn't follow the same syntactical rules. Here, cast looks like the 'scope()' or 'debug' statement, which should be followed by a body of code, but it works like a function which takes in the following argument and returns the result. Setting aside the "func!()()" syntax for a moment, what cast should look like in D is: int i = cast!int(myLong); It's a similar story with __traits(). What appears to be a function taking in a run-time parameter is actually compile-time parameter which works by "magic". It should look like: bool b = traits!HasMember(Foo); # FUNCTIONS PARAMETERS ## All that brings me to my next argument, and that's that the "func!()()" is inconsistent, or at the very least, hard to understand (when it doesn't have to be). We have one way of defining "optional" runtime parameters, and a different set of rules entirely for compile-time parameters. Granted, these things are very different to the compiler, to the programmer however, they "appear" to just be things we're passing to a function. I think Nimrod has a better (but not perfect) approach to this, in that there are different "kinds" of functions. One that takes in runtime params, and one that takes in compile-time ones; but at the call site, you use them the same: # Nimrod code template foo(x:int) # compile time when x == 0: doSomething() else: doSomethingElse() proc bar(x:int) # run time if x == 0: doSomething() else: doSomethingElse() block main: foo(0) # both have identical.. bar(0) # ..call signatures. In D, that looks like: void foo(int x)() { static if (x == 0) { doSomething(); } else { doSomethingElse(); } } void bar(int x) { if (x == 0) { doSomething(); } else { doSomethingElse(); } } void main() { foo!0(); bar(0); // completely difference signatures } Ultimately foo is just more optimized in the case where an 'int' can be passed at compile time, but the way you use it in Nimrod is much more consistent than in D. In fact, Nimrod code is very clean because there's no special syntax oddities, and that makes it easy to follow (at least on that level), especially for people learning the language. But I think there's a much better way. One of the things people like about Dynamicly Typed languages is that you can hack things together quickly. Given: function load(filename) { ... } the name of the parameter is all that's required when throwing something together. You know what 'filename' is and how to use it. The biggest problem (beyond efficiency), is later when you're tightening things up you have to make sure that 'filename' is a valid type, so we end up having to do the work manually where in a Strong Typed language we can just define a type: function load(filename) { if (filename != String) { error("Must be string"); return; } ... } vs: void load(string filename) { ... } but, of course, sometimes we want to take in a generic parameter, as D programmers are fully aware. In D, we have that option: void load(T)(T file) { static if (is(T : string)) ... else if (is(T : File)) ... } but it's wonky. Two parameter sets? Type deduction? These concepts aren't the easiest to pick up, and I remember having some amount of difficulty first learn what the "func!(...)(...)" did in D. So why not have one set of parameters and allow "typeless" ones which are simply compile-time duck-typ
Re: Consistency, Templates, Constructors, and D3
Typo: '_head' and '_next' in this example should be 'static' bleh.. I mean only '_head' should be static. Not '_next'
Re: Consistency, Templates, Constructors, and D3
F i L wrote: This would also keep consistent syntax when using FreeLists/MemeoryPools, because everything is done through factories in this case, and the implementation can be arbitrary: class Foo { private Foo _head, _next; [ ... ] Typo: '_head' and '_next' in this example should be 'static'