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: 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: 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: 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