Re: integral to floating point conversion

2016-07-02 Thread Simen Kjaeraas via Digitalmars-d
On Saturday, 2 July 2016 at 20:49:27 UTC, Andrei Alexandrescu 
wrote:

On 7/2/16 4:30 PM, Walter Bright wrote:

On 7/2/2016 1:17 PM, Andrei Alexandrescu wrote:
So what's the fastest way to figure that an integral is 
convertible to a
floating point value precisely (i.e. no other integral 
converts to the

same
floating point value)? Thanks! -- Andrei


Test that its absolute value is <= the largest unsigned value
represented by the float's mantissa bits.


What is the largest unsigned value represented by the float's 
mantissa bits? I recall there is a constant somewhere for it. 
-- Andrei


2uL^^float.mant_dig

And the same for double. For real (on x86), mant_dig is 64, so it 
can represent any ulong precisely.


--
  Simen


Re: Phobos: __FILE__ as template default parameter

2016-06-20 Thread Simen Kjaeraas via Digitalmars-d

On Monday, 20 June 2016 at 14:28:06 UTC, Jacob Carlborg wrote:


Would it be a bad idea to allow this in the compiler:

void foo(Args...)(Args args, string file = __FILE__, size_t 
line = __LINE__);


It wouldn't be possible to pass "file" or "line" when calling 
"foo". But it's useful for the special default values, __FILE__ 
and __LINE__.


I very much agree with this idea. Like with the current system of 
forwarding to a function with explicit file and line run-time 
arguments, a function can be made accessible that has them as 
explicit parameters for those cases when you want to pretend to 
be somewhere you're not. :p


--
  Simen


Re: C#7 features

2016-05-09 Thread Simen Kjaeraas via Digitalmars-d-announce

On Monday, 9 May 2016 at 00:44:09 UTC, Peter Häggman wrote:


Their tuples seem to be a complete DIY:

https://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx

I wouldn't be surpised to see in the implementation an array of 
variant or something like that, explaining why it's limited to 
octuples [1]. Sharp tuples look weak compared to D tuple-ish 
things: Tuple, TList, AliasSeq, variadics, ...


[1] Also I think that the param-"variadicity" is simply 
emulated via a set of overloaded constructor, explaining why 
they stop at 8.


C#'s tuples are actually 8 different templated classes - one for 
each arity. There's a lot of duplicated code to make that work. 
Wait, it's actually 9 classes - in addition to Tuple through 
Tuple there's the humble Tuple - a non-generic class 
that cannot be instantiated and only exists to be a namespace for 
the Tuple.Create function. The example code on gooroo seems to 
have eaten the template arguments for the constructor example - 
to instantiate a tuple you use one of these syntaxen:


  var t1 = new Tuple(1, "foo");
  var t2 = Tuple.Create(2, "bar");

The 'templates' in C# are (much) more limited than old C++ 
templates, and have nothing on D's templates. That's not 
necessarily a bad thing, though - the language is different and 
fills a different niche. It does mean some things that are very 
elegant in D end up very inelegant in C#, though.


Re: Accessing __FILE__ and __LINE__ of caller in combination with varargs?

2016-04-16 Thread Simen Kjaeraas via Digitalmars-d-learn
On Saturday, 16 April 2016 at 00:03:59 UTC, Jonathan M Davis 
wrote:
On Friday, April 15, 2016 20:52:42 WebFreak001 via 
Digitalmars-d-learn wrote:



void assertf(string file = __FILE__, size_t line = __LINE__,
Args...)(lazy bool condition, in string message, Args args) {


Yes, you can do that, but do _not_ do that unless you really 
have no other choice. What you need to realize is that because 
the file and line number arguments will be unique for every 
call to this function, it will generate a new instantiation of 
it _every_ time it is called. So, you're going to get a lot of 
code bloat. There are rare cases where such bloat would be 
acceptable, but in the general case, it's a terrible thing to 
do. This particular case might be acceptable given how short it 
is, but in general, using __FILE__ or __LINE__ as template 
arguments should be avoided like the plague.


A few tricks to reduce this bloat:

- Write a small wrapper. This will still give bloat, but only of
small functions:

void assertf(string file = __FILE__, size_t line = __LINE__, 
Args...)(lazy bool condition, in string message, Args args) {

assertfImpl(file, line, condition, message, args);
}

- Only care about line numbers in debug mode. Makes debug more 
bloated, code less readable, and you lose out on line numbers in 
release. Still worth it occasionally:


version (debug) {
void foo(string file = __FILE__, size_t line = __LINE__, 
Args...)(Args args) {

// Stuffs.
}
} else {
void assertf(Args...)(Args args) {
// Stuffs.
}
}

I'd love to have a way to pass the file and line number info as 
regular parameters, though. Something like:


void foo(Args...)(Args args, string file = __FILE__, int line = 
__LINE__) {}


Sadly, currently not possible. Maybe we could overload @disable 
for this purpose?


void foo(Args...)(Args args, @disable string file = __FILE__, 
@disable int line = __LINE__) {}


--
  Simen


Re: Opportunity: Software Execution Time Determinism

2016-04-13 Thread Simen Kjaeraas via Digitalmars-d

On Wednesday, 13 April 2016 at 22:58:26 UTC, Walter Bright wrote:
The compiler could be fairly easily compute cyclomatic 
complexity, but how that would be used to determine max time 
escapes me.


For example, how many times would a particular loop be 
executed? Isn't this the halting problem, i.e. not computable?


The first step is simple - we care only about functions being
constant-time. Let's invent a @keyword for that: @constanttime.

@constanttime functions can only call other functions marked
@constanttime, and may not contain conditionals, gotos or
while-loops.

@constanttime functions may contain for and foreach-loops, iff
the number of iterations are known at compile-time, and 'break'
is never used.

The part about conditionals seems a bit harsh, but it's got to
be there for determinism.

Constant time is easy, and may or may not be enough to cover
Nordlöw's needs. Anything beyond it is very likely to be halting
problem stuff.


Andrei has done some great work on determining big O complexity,
but that's only a small part of this problem.


I have a friend who works on timing attacks in cryptography. 
Knowing

the implementation and measuring the time it takes to multiply two
bigints can help you guess what the numbers are, so in his case
@constanttime would be exactly what he wants, while big-O would be
useless. Not knowing Nordlöw's use case I can't say for sure what 
he

actually needs.

--
  Simen


Re: Units of Measurement Library: units-d

2016-04-04 Thread Simen Kjaeraas via Digitalmars-d-announce

On Saturday, 2 April 2016 at 01:19:45 UTC, Meta wrote:

What is needed is Lisp's gensym construct.


That's basically what I said, no? :p

One problem of lisp's gensym (if we were to use it in D) is that 
it's simply a monotonically increasing number with a global 
prefix. It's perfect for the language it's in, and all but 
useless in D.


For this very reason, I have made a stab at implementing 
__GENSYM__ in D. It follows basically the ideas I outlined above, 
and spits out a string on the form MANGLE_#, with # being a 
counter for the given mangled name:


module bar;
struct Ham(string gensym = __GENSYM__) {
pragma(msg, gensym);
}
struct Eggs(string gensym = __GENSYM__) {
pragma(msg, gensym);
}

// ===

module foo;
import bar;

pragma(msg, __GENSYM__); // 3foo_1

void main() {
pragma(msg, __GENSYM__); // _Dmain_1
Ham!() a; // _Dmain_3bar_1
Ham!() b; // _Dmain_3bar_2
assert(!is(typeof(a) == typeof(b)));
Eggs!() c; // _Dmain_3bar_3
S2!() d; // _Dmain_3foo_1
}

struct Qux {
pragma(msg, __GENSYM__); // 3foo3Qux_1
void baz() {
pragma(msg, __GENSYM__); // _D3foo3Qux3bazMFZv_1
Ham!() a; // _D3foo3Qux3bazMFZv_3bar_1
}
}

struct S2(string gensym = __GENSYM__) {
pragma(msg, gensym);
}

Should I file an enhancement for this?

--
  Simen


Re: Units of Measurement Library: units-d

2016-04-01 Thread Simen Kjaeraas via Digitalmars-d-announce

On Friday, 1 April 2016 at 21:46:35 UTC, ag0aep6g wrote:

On 01.04.2016 22:59, Simen Kjaeraas wrote:
The usual way to fix it would be to include __FILE__ and 
__LINE__ in the

template arguments:


Right, no mixin this way. I wouldn't call this "truly nice", 
though.


It depends on code formatting to work. Put everything on one 
line and it breaks. Significant whitespace is a pain when 
generating code. Though this is not nearly as bad as 
significant indentation, of course.


__FILE__ also kind of breaks separate compilation. All object 
files have to be compiled from the same directory. Otherwise 
__FILE__ will be different.


__LINE__ has a similar (maybe even more obscure) issue. Add or 
remove a newline before compiling dependent modules and things 
break. Usually, one recompiles all dependents when a dependency 
changes, but a significant newline, really?


I kinda agree. And looking at https://dlang.org/spec/traits.html, 
I see there's __MODULE__, which would probably be a better choice 
than __FILE__.


As for __LINE__, what we'd want is basically something like 
__CONTEXT__, which doesn't exist, but might be the .mangleof of 
the surrounding scope:


struct S(string ctx = __CONTEXT__) {
pragma(msg, ctx);
}

S!() a; // "3foo"

void bar() {
S!() b; // "_D3foo3barFZv"
}

struct S2 {
S!() c; // "S3foo2S2"
void baz() {
S!() d; // "_D3foo2S23bazMFZv"
}
}

That'd remove the problem of significant whitespace. In fact, 
it'd also eliminate the need for __MODULE__ in this case.


Still though, that's not enough if we want this to work:

void foo() {
alias a = Foo!(); alias b = Foo!();
assert(!isSame!(a, b));
}

We could also add __COLUMN__, which would be the horizontal index 
of the instantiation's beginning:


foo(3, Bar!3.baz);
// ^Here. Position 11.

Next problem:

void main() {
pragma(msg, __LINE__);
mixin("pragma(msg, __LINE__);\npragma(msg, __LINE__);");
pragma(msg, __LINE__);
}

That prints '4' twice - once for the actual line 4, the other for 
the second line of the mixin. However, __FILE__ is different, so 
I guess __CONTEXT__ could also be.


--
  Simen


Re: Units of Measurement Library: units-d

2016-04-01 Thread Simen Kjaeraas via Digitalmars-d-announce

On Friday, 1 April 2016 at 19:03:03 UTC, ag0aep6g wrote:
I dislike that the type depends only on the given name. This 
effectively means that the names are in a global namespace.

[snip]
I can't think of a truly nice way to accomplish this, though. 
As far as I see, it needs a mixin of some kind.


The usual way to fix it would be to include __FILE__ and __LINE__ 
in the template arguments:


// In units/package.d:
struct BaseUnit(string name, string symbol = null, string file = 
__FILE__, size_t line = __LINE__)

{
   // ...
}

// in foo.d:
import experimental.units;
struct A
{
 // Actual type is BaseUnit!("Ampere", "A", "foo", 5):
alias BaseUnit!("Ampere", "A") Ampere;
enum ampere = Ampere.init;
}

struct B
{
 // Actual type is BaseUnit!("Ampere", "A", "foo", 12):
alias BaseUnit!("Ampere", "A") Ampere;
enum ampere = Ampere.init;
}

void main() {
assert(!is(B.Ampere == A.Ampere));
}

--
  Simen


Re: foreach_reverse and lockstep.

2016-04-01 Thread Simen Kjaeraas via Digitalmars-d

On Friday, 1 April 2016 at 17:44:40 UTC, ZombineDev wrote:

On Friday, 1 April 2016 at 16:10:01 UTC, Simen Kjaeraas wrote:
On Friday, 1 April 2016 at 14:37:36 UTC, Jonathan M Davis 
wrote:
(you'd need some sort of opApplyReverse function to go with 
foreach_reverse, and no such thing exists).


Actually, it exists and it works. It's just not implemented for
lockstep. I'm trying to clean up my Phobos repo so I can make a
PR to fix this. Apparently I need to learn more git. :)

--
  Simen


I'm already working on a PR. I think I can be ready by tomorrow.


Sure, but mine's ready now :p

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

--
  Simen


Re: foreach_reverse and lockstep.

2016-04-01 Thread Simen Kjaeraas via Digitalmars-d

On Friday, 1 April 2016 at 14:37:36 UTC, Jonathan M Davis wrote:
(you'd need some sort of opApplyReverse function to go with 
foreach_reverse, and no such thing exists).


Actually, it exists and it works. It's just not implemented for
lockstep. I'm trying to clean up my Phobos repo so I can make a
PR to fix this. Apparently I need to learn more git. :)

--
  Simen


Re: GC.malloc is pure - wat

2016-04-01 Thread Simen Kjaeraas via Digitalmars-d

On Friday, 1 April 2016 at 07:58:46 UTC, ZombineDev wrote:

On Friday, 1 April 2016 at 05:00:43 UTC, ag0aep6g wrote:

int[] f() pure nothrow {return [0];}

[snip]
The last case is different. It has nothing to do with pure. It 
is about reference-type literals and default field values:

[snip]

struct S
{
C c = new C;
int[] arr = [1, 2, 3];
}


No. Try this:


int[] bar() {
return [0];
}

void main() {
auto a = bar();
a[0] = 3;
auto b = bar();
assert(b[0] == 0);
}

That assert passes with flying colors no matter the compiler 
flags.


It is true that arrays in structs' initial state are copied (and 
may lead to subtle bugs), but the same is not the case for arrays 
returned from functions.


--
  Simen


Re: infer type argument in classe constructor?

2016-03-29 Thread Simen Kjaeraas via Digitalmars-d-learn

On Tuesday, 29 March 2016 at 10:13:28 UTC, Puming wrote:

Hi,

I'm writing a generic class:

```d

struct Message { ... }

class Decoder(MsgSrc) {
}
```

When using it, I'd have to include the type of its argument:

```
void main() {
   Message[] src = ...;

   auto decoder = new Decoder!(Message[])(src);

   ...
}
```

Can it be inferred so that I only need to write?

```d
auto decoder = new Decoder(src); // you can infer the type from 
src.

```


Nope. To see why, consider a class like this:

class A(T) {
  T data;
  this(int n) {
  }
}

void main() {
   auto a = new A(3); // What is T?
}

The common solution is a simple 'create' function:

Decoder!T decoder(T)(T msg) {
return new Decoder!T(msg);
}

--
  Simen


Re: [Blog post] Why and when you should use SoA

2016-03-26 Thread Simen Kjaeraas via Digitalmars-d-announce

On Friday, 25 March 2016 at 01:07:16 UTC, maik klein wrote:

Link to the blog post: https://maikklein.github.io/post/soa-d/
Link to the reddit discussion: 
https://www.reddit.com/r/programming/comments/4buivf/why_and_when_you_should_use_soa/


Neat. I've actually thought about writing exactly this kind of 
template for the fun of it. Thank you for showing how it'd work.


Btw, your use of Tuple!ArrayTypes for the 'containers' field 
strikes me as unnecessary, as ArrayTypes on its own would cover 
all your use cases.


--
  Simen


Re: A Huge Bummer When Using alias this

2016-03-24 Thread Simen Kjaeraas via Digitalmars-d

On Thursday, 24 March 2016 at 21:26:00 UTC, Jack Stouffer wrote:
alias this is only useful when not using any function that 
relies on the template constraints in std.traits.


For example

import std.traits;

void someFunc(N)(N val) if (isNumeric!N)
{
int b = val;
}

void main()
{
import std.typecons;
Nullable!int a = 42;

someFunc(a);
}

$ dmd test.d
test.d(13): Error: template someFunc cannot deduce function 
from argument types !()(Nullable!(int))


Removing the template constraint makes it compile and run just 
fine. What's a good work around for these types of issues?


Simply put, isNumeric doesn't do what you think it does. It 
checks if the type is *exactly* one of the built-in numeric types 
(ints and floats of various known-at-compile-time sizes). Even 
BigInt, a part of Phobos that is explicitly supposed to work as a 
numeric thing, is not numeric accordion to isNumeric.


IMO, isNumeric should be renamed isBuiltInNumeric or something to 
that effect, as it obviously does not test what it says it does. 
In addtion, there should be a function somewhat like 
numericBehavior below:


template supportsBinOp(string op, T, U = T) {
enum supportsBinOp = __traits(compiles, (T t, U u) {
return mixin("t "~op~" u");
});
}

template supportsUnOp(string op, T) {
enum supportsUnOp = __traits(compiles, (T t) {
return mixin(op~" t");
});
}

template numericBehavior(T) {
enum numericBehavior =
supportsBinOp!("+", T) &&
supportsBinOp!("+", T, int) &&
supportsBinOp!("-", T) &&
supportsBinOp!("-", T, int) &&
supportsBinOp!("*", T) &&
supportsBinOp!("*", T, int) &&
supportsBinOp!("*", T) &&
supportsBinOp!("*", T, int) &&
supportsBinOp!("+=", T) && // Should opOpAssign be 
required?

supportsBinOp!("+=", T, int) &&
supportsBinOp!("-=", T) &&
supportsBinOp!("-=", T, int) &&
supportsBinOp!("*=", T) &&
supportsBinOp!("*=", T, int) &&
supportsBinOp!("*=", T) &&
supportsBinOp!("*=", T, int) &&
  //supportsUnOp!("++", T) && // Should these
  //supportsUnOp!("-+", T) && // be included?
supportsUnOp!("+", T) &&
supportsUnOp!("-", T);
} unittest {
import std.typecons : Nullable;
import std.bigint : BigInt;
import std.meta : AliasSeq;
import std.complex : Complex;

alias goodTypes = AliasSeq!(
byte, short, int, long,
ubyte, ushort, uint, ulong,
float, double, real,
BigInt, Nullable!int,
Complex!float
);

foreach (e; goodTypes) {
static assert(numericBehavior!e, "Expected "~e.stringof~" 
to have numeric behavior,");

}

alias badTypes = AliasSeq!(
string, int*, Object, void, Nullable!string,
immutable int // Should this be on the list?
);

foreach (e; badTypes) {
static assert(!numericBehavior!e, "Did not expect 
"~e.stringof~" to have numeric behavior,");

}
}

This tests for behavior, not simply type. I'm not saying 
isNumeric is a bad template, it just has a confusing name.


Re: Does something like std.algorithm.iteration:splitter with multiple seperators exist?

2016-03-23 Thread Simen Kjaeraas via Digitalmars-d-learn

On Wednesday, 23 March 2016 at 18:10:05 UTC, ParticlePeter wrote:

Thanks Simen,
your tokenCounter is inspirational, for the rest I'll take some 
time for testing.


My pleasure. :) Testing it on your example data shows it to work 
there. However, as stated above, the documentation says it's 
undefined, so future changes (even optimizations and bugfixes) to 
Phobos could make it stop working:


"This predicate must be an equivalence relation, that is, it must 
be reflexive (pred(x,x) is always true), symmetric (pred(x,y) == 
pred(y,x)), and transitive (pred(x,y) && pred(y,z) implies 
pred(x,z)). If this is not the case, the range returned by 
chunkBy may assert at runtime or behave erratically."



But some additional thoughts from my sided:
I get all the lines of the file into one range. Calling array 
on it should give me an array, but how would I use find to get 
an index into this array?
With the indices I could slice up the array into four slices, 
no allocation required. If there is no easy way to just get an 
index instead of an range, I would try to use something like 
the tokenCounter to find all the indices.


The chunkBy example should not allocate. chunkBy itself is lazy, 
as are its sub-ranges. No copying of string contents is 
performed. So unless you have very specific reasons to use 
slicing, I don't see why chunkBy shouldn't be good enough.


Full disclosure:
There is a malloc call in RefCounted, which is used for 
optimization purposes when chunkBy is called on a forward range. 
When chunkBy is called on an array, that's a 6-word allocation 
(24 bytes on 32-bit, 48 bytes on 64-bit), happening once. There 
are no other dependencies that allocate.


Such is the beauty of D. :)

--
  Simen


Re: Does something like std.algorithm.iteration:splitter with multiple seperators exist?

2016-03-23 Thread Simen Kjaeraas via Digitalmars-d-learn

On Wednesday, 23 March 2016 at 11:57:49 UTC, ParticlePeter wrote:
I need to parse an ascii with multiple tokens. The tokens can 
be seen as keys. After every token there is a bunch of lines 
belonging to that token, the values.

The order of tokens is unknown.

I would like to read the file in as a whole string, and split 
the string with:

splitter(fileString, [token1, token2, ... tokenN]);

And would like to get a range of strings each starting with 
tokenX and ending before the next token.


Does something like this exist?

I know how to parse the string line by line and create new 
strings and append the appropriate lines, but I don't know how 
to do this with a lazy result range and new allocations.


Without a bit more detail, it's a bit hard to help.

std.algorithm.splitter has an overload that takes a function 
instead of a separator:


import std.algorithm;
auto a = "a,b;c";
auto b = a.splitter!(e => e == ';' || e == ',');
assert(equal(b, ["a", "b", "c"]));

However, not only are the separators lost in the process, it only 
allows single-element separators. This might be good enough given 
the information you've divulged, but I'll hazard a guess it isn't.


My next stop is std.algorithm.chunkBy:

auto a = ["a","b","c", "d", "e"];
auto b = a.chunkBy!(e => e == "a" || e == "d");
auto result = [
tuple(true, ["a"]), tuple(false, ["b", "c"]),
tuple(true, ["d"]), tuple(false, ["e"])
];

No assert here, since the ranges in the tuples are not arrays. My 
immediate concern is that two consecutive tokens with no 
intervening values will mess it up. Also, the result looks a bit 
messy. A little more involved, and according to documentation not 
guaranteed to work:


bool isToken(string s) {
return s == "a" || s == "d";
}

bool tokenCounter(string s) {
static string oldToken;
static bool counter = true;
if (s.isToken && s != oldToken) {
oldToken = s;
counter = !counter;
}
return counter;
}

unittest {
import std.algorithm;
import std.stdio;
import std.typecons;
import std.array;

auto a = ["a","b","c", "d", "e", "a", "d"];
auto b = a.chunkBy!tokenCounter.map!(e=>e[1]);
auto result = [
["a", "b", "c"],
["d", "e"],
["a"],
["d"]
];
writeln(b);
writeln(result);
}

Again no assert, but b and result have basically the same 
contents. Also handles consecutive tokens neatly (but consecutive 
identical tokens will be grouped together).


Hope this helps.

--
  Simen


Re: How do I extend an enum?

2016-03-19 Thread Simen Kjaeraas via Digitalmars-d-learn

On Saturday, 19 March 2016 at 17:40:27 UTC, Lass Safin wrote:

Why:

enum Base {
A,
B,
}

enum Derived : Base {
C, // Gives error, says it can't implicitly convert 
expression to Base.

D = 1, // Same error
E = cast(Base)294, // Finally works. Can only be 
cast(Derived) instead.

}

void func(Derived d) {}

func(Derived.E); // works.
func(Derived.A); // Gives error, says it can't call function 
with Base.A.

func(cast(Derived)Derived.A); // Works.

So, what's the proper way of extending an enum?


There is no way to extend an enum. When you think about it, it's 
actually the opposite of what you'd generally want. Given  two 
classes:


class A {}
class B : A {}

Every instance of B is a valid A. That is, given a variable of 
type A, you could assign any B to it.


Now consider enums:

enum A { x, y, z }
enum B : A {}

Which values could you put in B? Only those that would be valid 
for A. That is, only x, y and z. Imagine that we could:


enum B : A { w }

A foo = B.w;

foo now holds a value that is not valid for its type. Hence, you 
simply cannot.


Are there cases where you want to define a new enum that contains 
all the items in a 'base' enum in addition to some new items? 
Absolutely, and D lacks a good way to do that. But subtyping 
would in any case not be the correct way to do it.


Are there cases where you want to extend an enum by making a 
subtype with more items? I would argue that's a strong code smell 
in D, but I can see why you'd want to.


--
  Simen


Re: Pattern matching as a library

2016-03-13 Thread Simen Kjaeraas via Digitalmars-d

On Sunday, 13 March 2016 at 02:33:49 UTC, Simen Kjaeraas wrote:

http://dpaste.dzfl.pl/7360ee90b344


Dammit, 3:30AM was apparently too late, and some bad code leaked 
through. I managed to sidestep a problem by writing nonsense 
code. The problem I get can be reduced to this:


struct S {
void foo(alias a)() {}
}

unittest {
S s;
s.foo!((int i) => 1); // Works
s.foo!(i => 1); // Fails
}

Result:
foo.d(8): Error: template instance foo!((i) => 1) cannot use 
local '__lambda1' as parameter to non-global template foo(alias 
a)()


Bah. It's in bugzilla as bug 5710[1] (with the most discussion), 
3051, 3052, 11098, 12285, 12576 and 15564, and has a $150 bounty 
on bountysource:

https://www.bountysource.com/issues/1375082-cannot-use-delegates-as-parameters-to-non-global-template

Maybe it's time I learnt how DMD is put together and earn $150...


Now, there's a way to work around that, by putting the lambda in 
an intermediate type. Sadly, that runs afoul of bug 15794[2] for 
the typed lambda, so I'm stumped for now.


[1]: https://issues.dlang.org/show_bug.cgi?id=5710
[2]: https://issues.dlang.org/show_bug.cgi?id=15794


Re: Pattern matching as a library

2016-03-12 Thread Simen Kjaeraas via Digitalmars-d

On Saturday, 12 March 2016 at 20:56:47 UTC, Jacob Carlborg wrote:

On 12/03/16 14:12, Simen Kjaeraas wrote:
As I once again bemoaned D's lack of pattern matching 
yesterday, I was
inspired to create this[0] implementation, that plays to D's 
strengths,
allows for user-defined matching, and has a fairly usable 
syntax. The

core usage looks like this:

unittest {
   auto a = tuple(1, "foo");
   auto b = match(a) (
 _!(int, "foo") = (int i) => 1,
 _!(_, _)   = ()  => 0
   );
   assert(b == 1);
}


What kind of syntax is that? Is "match" returning a struct with 
opCall that is called immediately?


Indeed. The goal was to make it look similar to a switch 
statement. I actually started out with an idea for expanding 
switch with pattern matching using lowerings, then noticed I 
could do most of the stuff I wanted without compiler changes.




With the user-defined matching implemented as follows:

struct Tuple(T...) {
// Implementation

   // Magic happens here
   bool opMatch(Pattern, Args...)(Pattern p, ref Args args) {
 foreach (i, e; p.pattern) {
   static if (isTypeTuple!e) {
 enum n = countTypes!(p.pattern[0..i]);
 args[n] = fields[i];
   } else static if (!ignore!e) {
 if (fields[i] != e) {
   return false;
 }
   }
 }
   }
}


Is the tuple iterating all patterns to see if there's a match? 
Shouldn't that be the job for the the match function?


The match function goes through the list of patterns and for each 
one asks the tuple if opMatch returns true for that pattern. If 
it does, the function assigned that pattern is called with the 
values assigned to args.


opMatch here is checking for each element of the pattern if it 
matches the corresponding element of the tuple. Since the pattern 
is available at compile-time, opMatch can deny patterns it 
doesn't like (e.g. trying to match a Tuple!(int, string) with a 
string).


The match function is really only a framework for having similar 
matching syntax for dissimilar types.


If the capability of matching patterns to types were in the match 
function, how could a user type override it? Matching on a 
Tuple!(string, string) is different from matching on an 
Algebraic!(int[], Foo*) is different from matching on a 
specialized user type that wants to do something real weird (I'm 
not sure what that'd be, but I'm sure there are people who will 
want to).



I've started implementing a pattern matching function as well. 
It has a syntax that only use compile time parameters, because 
both types and values can be passed. I'm not entirely sure on 
the syntax yet. I'll have to see what's possible to implement. 
Some suggestions:


auto a = tuple(1, "foo");
auto b = match!(a,
int, "foo", (int i) => 1,
_, _, () => 0,
);


That works. I feel the grouping is looser than in my example, and 
that the pattern doesn't stand out from the rest of the 
expression, but it certainly works, and there are some benefits 
to that syntax.



If the pull request for inspecting templates ever will be 
merged it won't be necessary to have typed lambdas:


auto b = match!(a,
int, "foo", (i) => 1,
_, _, () => 0,
);


There's a problem using that syntax? It works for me in a toy 
example:


http://dpaste.dzfl.pl/7360ee90b344

Sorry about the lack of comments and stuff, but it's 3:30AM, and 
I probably shouldn't be programming now.


Pattern matching as a library

2016-03-12 Thread Simen Kjaeraas via Digitalmars-d
As I once again bemoaned D's lack of pattern matching yesterday, 
I was inspired to create this[0] implementation, that plays to 
D's strengths, allows for user-defined matching, and has a fairly 
usable syntax. The core usage looks like this:


unittest {
  auto a = tuple(1, "foo");
  auto b = match(a) (
_!(int, "foo") = (int i) => 1,
_!(_, _)   = ()  => 0
  );
  assert(b == 1);
}

With the user-defined matching implemented as follows:

struct Tuple(T...) {
   // Implementation

  // Magic happens here
  bool opMatch(Pattern, Args...)(Pattern p, ref Args args) {
foreach (i, e; p.pattern) {
  static if (isTypeTuple!e) {
enum n = countTypes!(p.pattern[0..i]);
args[n] = fields[i];
  } else static if (!ignore!e) {
if (fields[i] != e) {
  return false;
}
  }
}
  }
}

Or for Algebraic:

struct Algebraic(T...) {
  union {
T fields;
  }
  size_t which;

  bool opMatch(Pattern, Type)(Pattern p, ref Type args) if 
(staticIndexOf!(Type, T) > -1) {

enum index = staticIndexOf!(Type, T);
if (index == which) {
  args = fields[index];
  return true;
}
return false;
  }
}

The main problem I see is the temporary allocation of function 
arguments on line 124 and their assignment in opMatch, but I 
currently don't have a better solution.


Also, while I very much dislike using _ for an identifier, I feel 
it may be the best alternative here - it conveys the meaning of 
'don't care' for the pattern, and doesn't stand out like a sore 
thumb before the exclamation mark. Other suggestions are welcome.


The code is available here, and I encourage everyone to play with 
it and critique:


[0]: 
https://github.com/Biotronic/Collectanea/blob/master/biotronic/pattern.d


Re: Members as first class citizens!

2016-02-27 Thread Simen Kjaeraas via Digitalmars-d

On Saturday, 27 February 2016 at 18:48:27 UTC, Patience wrote:

Ok, maybe not but this is what I mean:

Why can't we pass member as as sort of "objects" in there own 
right to be used for accessing objects?


e.g.,

class A
{
   int? foo;
   A Parent;

   T GetAncestorValue(member field) // member is a new 
keyword

   {
   var p = this;
   while (!p && !p.field.HasValue)
   {
   p = p.Parent;
   }
   return p.field.Value;
   }
}

(This is pseudo D/C# code)


Then

auto x = a.GetAncestorValue(A:foo) would the properly 
initialized x.


The code is simple, logical, and makes sense(since foo is just 
an "offset" and a type. It has type safety and doesn't resort 
to reflection and passing members as strings, etc. It allows 
for general access of members rather than having to jump 
through a bunch of hoops. It should be much faster too.


Is there any fundamental theoretical reason why such a semantic 
could not be implemented in current object oriented compilers?


There is absolutely no technical reason, no. C++ actually has 
this feature. The reason it has not been implemented in D is it's 
a (very) rarely used feature in other languages and perfectly 
possible to implement type-safely and efficiently in a library:


struct nullable(T) {
T value;
bool hasValue = false;
}

class A {
   nullable!int foo;
   A parent;

   auto GetAncestorValue(T...)(Member!T field) {
   auto p = this;
   while (p && !field(p).hasValue) {
   p = p.parent;
   }
   return field(p).value;
   }
}

struct Member(T, U) {
private int fieldId;

@disable this();

private this(int id) {
fieldId = id;
}

auto opCall(T that) {
foreach (i, e; __traits(allMembers, T)) {
static if (is(typeof(__traits(getMember, that, e)) == 
U)) {

if (i == fieldId) {
return __traits(getMember, that, e);
}
}
}
assert(false);
}
}

template member(alias m) {
import std.typetuple : TypeTuple;
alias parentMembers = TypeTuple!(__traits(allMembers, 
__traits(parent, m)));

template memberIndex(int n) {
static if (parentMembers[n] == __traits(identifier, m)) {
enum memberIndex = n;
} else {
enum memberIndex = memberIndex(n+1);
}
}
enum member = Member!(__traits(parent, m), 
typeof(m))(memberIndex!0);

}

void main() {
A a = new A();
A b = new A();
a.parent = b;
b.foo.hasValue = true;
b.foo.value = 3;
a.foo.value = 15;

assert(a.GetAncestorValue(member!(A.foo)) == 3);
}

Now, you lose the 'p.field' sugar, and it's possible the built-in 
feature could drop some safeguards in release mode to make it 
more efficient, but this should cover most of your concerns.


--
  Simen


Re: extern(C++, ns)

2016-01-20 Thread Simen Kjaeraas via Digitalmars-d

On Wednesday, 20 January 2016 at 12:47:44 UTC, Manu wrote:

2. Multiple modules cannot have the same name in D.



I'm not sure what situation you're imagining where modules 
would be created with the same names...?




How do you plan to map C++'s standard lib ? One giant hundred 
of thousands of line C++ file ?


Surely it would map by file.

#include  -> import stl.vector;
#include  -> import stl.map;
#include  -> import stl.string;

Perhaps 'stl' may be something else, 'std' is an unfortunate 
conflict with phobos, but this is unique to this case.


I believe deadalnix here meant something like this:

  import stl.vector;
  import mylib.vector;

  Vector a; // Ambiguous: could be from mylib or stl
  stl.Vector b; // Error: no such class stl.Vector
  stl.vector.Vector c; // Works, but requires extra typing

Which with working namespaces might allow case b to work.

--
  Simen


Re: extern(C++, ns)

2016-01-20 Thread Simen Kjaeraas via Digitalmars-d

On Wednesday, 20 January 2016 at 23:35:31 UTC, Manu wrote:
On 21 January 2016 at 01:32, Simen Kjaeraas via Digitalmars-d 
<digitalmars-d@puremagic.com> wrote:

On Wednesday, 20 January 2016 at 12:47:44 UTC, Manu wrote:


2. Multiple modules cannot have the same name in D.




I'm not sure what situation you're imagining where modules 
would be created with the same names...?




How do you plan to map C++'s standard lib ? One giant 
hundred of thousands of line C++ file ?



Surely it would map by file.

#include  -> import stl.vector;
#include  -> import stl.map;
#include  -> import stl.string;

Perhaps 'stl' may be something else, 'std' is an unfortunate 
conflict with phobos, but this is unique to this case.



I believe deadalnix here meant something like this:

  import stl.vector;
  import mylib.vector;

  Vector a; // Ambiguous: could be from mylib or stl
  stl.Vector b; // Error: no such class stl.Vector
  stl.vector.Vector c; // Works, but requires extra typing


Okay let me tweak your code:

   import stl.vector;
   import stl.string;   // one more thing; when do you ever only
import a single module?
   import mylib.vector;

   Vector a; // Ambiguous: could be from mylib or stl
   stl.Vector b; // Error: this wouldn't work, becase stl could 
be stl.vector.stl or stl.map.stl

   stl.vector.Vector c; // This is what a D programmer expects,
exactly like every other conflict resolution in D ever, but it 
doesn't work either


[snip]


Which with working namespaces might allow case b to work.


I hope I've shown how it almost never does, and only makes the 
situation worse.


I'm playing devil's advocate here, since I fully agree with you
that there is absolutely no need for C++ namespaces in D, and
that the cost in language complexity is too high.

Suppose that case b above worked, though - instead of a conflict,
lookup would basically merge namespaces with the same name, and
only conflict if there are multiple definitions that are not
namespaces.

On the one hand, I hope that's how it's supposed to work,
otherwise it's just silly. On the other hand, that's a clear break
with D's current lookup rules, and for what I consider very, very
little benefit.

--
  Simen


Re: classInstanceSize and vtable

2014-10-24 Thread Simen Kjaeraas via Digitalmars-d-learn

On Friday, 24 October 2014 at 00:21:52 UTC, Etienne Cimon wrote:

On 2014-10-23 20:12, bearophile wrote:
In D all class instances contain a pointer to the class and a 
monitor
pointer. The table is used for run-time reflection, and for 
standard

virtual methods like toString, etc.

Bye,
bearophile


So what's the point of making a class or methods final? Does it 
only free some space and allow inline to take place?


Like bearophile said the vtable is required for virtual methods. 
Consider this code:


import std.stdio : writeln;

class A { void foo() {writeln(A);} }
final class B : A { override void foo() {writeln(B);} }

void main() {
A a = new B();
a.foo();
}

In order for the call to foo to run the correct version of foo, B 
needs to have a vtable. Since all classes in D implicitly inherit 
from Object, which has some virtual methods, all classes need to 
have a vtable.


--
  Simen