Re: Dub, Cargo, Go, Gradle, Maven

2018-02-14 Thread Graham St Jack via Digitalmars-d
On Tue, 13 Feb 2018 10:21:49 +, Abdulhaq wrote:

> On Tuesday, 13 February 2018 at 10:06:43 UTC, welkam wrote:
>> ADG? Google doesnt find anything relevant
> 
> Acyclic directed graph

A.K.A "DAG" - directed acyclic graph.

I am also interested in build systems, and am currently convinced that 
the problem space is complex enough to warrant build systems being 
separate from package management systems.

Maybe a compromise position would be for a package management system to 
define an interface through which it can do things like:

* Discover what the external dependencies are,

* Provide those external dependencies, and

* Invoke a full build.

Then, any number of build systems (and deployment systems?) could be 
adapted to work with the package management system.


Re: Announcing bottom-up-build - a build system for C/C++/D

2013-06-30 Thread Graham St Jack
On Thu, 27 Jun 2013 22:49:41 +, Graham St Jack wrote:

 On Thu, 27 Jun 2013 07:44:07 +0200, Rob T wrote:
 
 This build system seems to be very well suited for building complex
 large projects in a sensible way.
 
 I successfully tested the example build on Debian linux. I will
 definitely explore this further using one of my own projects.
 
 One issue I immediately ran into, is when I run bub incorrectly it
 hangs after writing the bail message to console. ctrl-c does not kill
 it, and I have to run a process kill commandto terminate.
 
 Seems it gets stuck in doBailer() while(true) loop, but I only glanced
 at the source quickly before posting back here.
 
 --rt
 
 I recently made a big change to the inter-thread communication code, and
 there are a few problems there still. I will look into it.

Fixed the problem, and also:

* split bub.d up into several smaller files,

* added a Makefile to bootstrap the building of bub, and

* added a bub.cfg and Bubfile as a trivial example of how to use bub.


Re: Announcing bottom-up-build - a build system for C/C++/D

2013-06-29 Thread Graham St Jack
On Sat, 29 Jun 2013 00:59:15 +0200, John Colvin wrote:

 On Thursday, 27 June 2013 at 00:10:37 UTC, Graham St Jack wrote:
 Having side-by-side comparisons of D against bash scripts and C++
 modules had the effect of turning almost all the other team members
 into D advocates.
 
 Any chance we could know what team this is? (Sorry if this is common
 knowledge)

It is the development team at my previous workplace. I haven't asked them 
for permission, so I would rather not say who they are.

David Bryant (the previous poster) was a member of that team though, and 
he will be happy to provide details.


Re: Announcing bottom-up-build - a build system for C/C++/D

2013-06-28 Thread Graham St Jack
On Fri, 28 Jun 2013 08:05:08 +0200, Rob T wrote:

 On Thursday, 27 June 2013 at 23:03:40 UTC, Graham St Jack wrote:

 This isn't a build tool for everyone, but it really does make a big
 difference on big projects.
 
 Well I'm noticing some interesting concepts, such as being able to
 associate an include or import file with the library to link in, so that
 it gets done automatically simply by using the include/import file,
 great idea assuming I understood that correctly.

That is correct. A side effect of assigning headers to libraries is that 
bub can then enforce the visibility rules and give understandable error 
messages almost instantaneously when you transgress them. Another 
consequence is that the compiler only needs to be given a few -I 
directives because you aren't using them to control visibility.

 
 One thing you may want to consider, or maybe this is already possible,
 is add the ability to optionally specify something like *.d so that all
 .d files get included from a folder, rather than have to always
 individually specify them manually.

A useful idea. I will add it to the list.

 
 Also more concise documentation with clearer examples would be
 invaluable. I'm currently unsure if I need to restructure my existing
 project folders to fit bub or if bub can be configured to fit my
 existing projects.

Documentation is always tough to pitch at the right level. I will see 
what I can do.

Whether you need to restructure your project depends on whether you have 
already thought about dependencies and arranged things accordingly.

My suggestion is to extend the example a bit and get a feel for how it 
works, then think about what that means for your project.



Re: Announcing bottom-up-build - a build system for C/C++/D

2013-06-28 Thread Graham St Jack
On Fri, 28 Jun 2013 08:28:03 +0200, Marco Leise wrote:

 How does this build tool handle projects with multiple executables ? For
 example the util-linux package contains dozens of utilities or a project
 might have a CLI and a GUI version. Or there might be slight alterations
 like setting a version or debug flag: -debug=threading -version=demo


A central theme in bottom-up-build is to produce any number of build 
artifacts: libraries, executables, tests, etc.

Different versions are catered for with:
  bub-config --mode=whatever build-dir

The mode is described in your configuration file, and results in a build 
directory set up specifically for that mode.

If you want multiple modes, use multiple build directories.

Take a look in example/bub.cfg.


Re: Announcing bottom-up-build - a build system for C/C++/D

2013-06-27 Thread Graham St Jack
On Thu, 27 Jun 2013 07:44:07 +0200, Rob T wrote:

 This build system seems to be very well suited for building complex
 large projects in a sensible way.
 
 I successfully tested the example build on Debian linux. I will
 definitely explore this further using one of my own projects.
 
 One issue I immediately ran into, is when I run bub incorrectly it hangs
 after writing the bail message to console. ctrl-c does not kill it,
 and I have to run a process kill commandto terminate.
 
 Seems it gets stuck in doBailer() while(true) loop, but I only glanced
 at the source quickly before posting back here.
 
 --rt

I recently made a big change to the inter-thread communication code, and 
there are a few problems there still. I will look into it.


Announcing bottom-up-build - a build system for C/C++/D

2013-06-26 Thread Graham St Jack
Bottom-up-build (bub) is a build system written in D which supports 
building of large C/C++/D projects. It works fine on Linux, with a 
Windows port nearly completed. It should work on OS-X, but I haven't 
tested it there. 

Bub is hosted on https://github.com/GrahamStJack/bottom-up-build.


Some of bub's features that are useful on large projects are:

Built files are located outside the source directory, using a different 
build directory for (say) debug, release, profile, etc.

Very simple configuration files, making the build infrastructure easy to 
maintain.

Automatic deduction of which libraries to link with.

Automatic execution and evaluation of tests.

Enforcement of dependency control, with prevention of circularities 
between modules and directories.

Generated files are not scanned for imports/includes until after they are 
up to date. This is a real enabler for code generation.

Files in the build directory that should not be there are automatically 
deleted. It is surprising how often a left-over build artifact can make 
you think that something works, only to discover your mistake after a 
commit. This feature eliminates that problem.

The dependency graph is accurate, maximising opportunity for multiple 
build jobs and thus speeding up builds significantly.


An early precursor to bub was developed to use on a large C++ project 
that had complex dependencies and used a lot of code generation. Bub is a 
major rewrite designed to be more general-purpose.

The positive effect of the bub precursor on the project was very 
significant. Examples of positive consequences are:

Well-defined dependencies and elimination of circularities changed the 
design so that implementation and testing proceeded from the bottom up.

Paying attention to dependencies eliminated many unnecessary ones, 
resulting in a substantial increase in the reusability of code. This was 
instrumental in changing the way subsequent projects were designed, so 
that they took advantage of the large (and growing) body of reusable code.
The reusable code improved in design and quality with each project that 
used it.

Tests were compiled, linked and executed very early in the build - 
typically immediately after the code under test. This meant that 
regressions were usually detected within a few seconds of initiating a 
build. This was transformative to work rate, and willingness to make 
sweeping changes.

Doing a clean is hardly ever necessary. This is important because it 
dramatically reduces the total amount of time that builds take, which 
matters on a large project (especially C++).

Having a build system that works with both C++ and D meant that it was 
easy to slip some D code into the project. Initially as scripts, then 
as utilities, and so on. Having side-by-side comparisons of D against 
bash scripts and C++ modules had the effect of turning almost all the 
other team members into D advocates.


Re: Formal Review of std.process

2013-04-07 Thread Graham St Jack
Not sure if this is the right place for this, but I have found a 
problem in my fairly old version of the new process module. The 
problem was in the POSIX spawnProcessImpl() just after the fork() 
call in the child process branch.


The child would occasionally block forever on an attempt by the D 
code to lock a mutex.


The problem went away when I moved the toStringx() and toArgz() 
calls to before the fork() call.


I have no idea what is going on here, but it seems like fork() 
leaves the child in bad shape, so my 'fix' is very much a 
band-aid.


Re: New std.process?

2013-02-11 Thread Graham St Jack
On Sun, 03 Feb 2013 19:56:54 +, Dejan Lekic wrote:

 simendsjo wrote:
 
 On Saturday, 20 October 2012 at 18:17:31 UTC, Alex Rønne Petersen
 wrote:
 It's time for the periodic new std.process ping. ;)

 Seriously, though, what's the state of it? Can we get it into the
 review queue soon? It would be great to have it in 2.060.
 
 I just created a small script using std.process, and the *pain*.. Took
 a look at the new std.process which easily lets you spawn a process
 using custom stdin/out/err, get the result etc.etc.. Looks a lot better
 than what we currently have.
 
 Unfortunately, it needs some druntime changes, so I couldn't just plug
 it in without building dmd myself.
 
 So.. Ping? :) Inclusion in 2.062?
 
 +1 I join Alex on this. I can't wait for improved std.process,
 honestly...

+1. I have been using a hacked copy of the new one for ages, and would 
love to see it become part of phobos.


Re: Something needs to happen with shared, and soon.

2012-11-11 Thread Graham St Jack
On Sun, 11 Nov 2012 22:19:08 +0100, martin wrote:

 On Sunday, 11 November 2012 at 20:08:25 UTC, Benjamin Thaut wrote:
 Fully agree.
 
 +1

+1.

I find it so broken that I have to avoid using it in all but the most 
trivial situations.


Re: New std.process?

2012-10-21 Thread Graham St Jack
On Sun, 21 Oct 2012 21:36:32 +0400, Denis Shelomovskij wrote:

 21.10.2012 1:52, David Nadlinger пишет:
 On Saturday, 20 October 2012 at 18:56:01 UTC, Alex Rønne Petersen
 wrote:
 Oh, and could somebody please post a link to the latest version of the
 new std.process draft? I will probably add cross-platform support for
 constraining execution time and resource (RAM, mostly) usage, but there
 is no point in reimplementing it if it's already there.

 David
 
 Probably original discussion with links:
 http://www.digitalmars.com/d/archives/digitalmars/D/
The_new_std.process_163694.html
 
 Links from that thread:
 * std.process overhaul:
 https://github.com/kyllingstad/phobos/commits/new-std-process * druntime
 changes:
 https://github.com/schveiguy/druntime/commits/new-std-process
 

I am also hanging out for the new std.process. Any idea when the required 
druntime changes will go in, or if they have already?


Re: Message passing between threads: Java 4 times faster than D

2012-02-09 Thread Graham St Jack
I suggest using a template-generated type that can contain any of the 
messages to be sent over a channel. It is reasonably straightforward to 
generate all the boilerplate code necessary to make this happen. My 
prototype (attached) still needs work to remove linux dependencies and 
tighten it up, but it works ok. Another advantage of this approach 
(well, I see it as an advantage) is that you declare in a single 
location all the messages that can be sent over the channel, and of 
course the messages are type-safe.


The file of interest is concurrency.d.

On 10/02/12 02:14, Sean Kelly wrote:

So a queue per message type?  How would ordering be preserved? Also, how would 
this work for interprocess messaging?  An array-based queue is an option 
however (though it would mean memmoves on receive), as are free-lists for 
nodes, etc.  I guess the easiest thing there would be a lock-free shared slist 
for the node free-list, though I couldn't weigh the chance of cache misses from 
using old memory blocks vs. just expecting the allocator to be fast.

On Feb 9, 2012, at 6:10 AM, Gor Gyolchanyangor.f.gyolchan...@gmail.com  wrote:


Generally, D's message passing is implemented in quite easy-to-use
way, but far from being fast.
I dislike the Variant structure, because it adds a huge overhead. I'd
rather have a templated message passing system with type-safe message
queue, so no Variant is necessary.
In specific cases Messages can be polymorphic objects. This will be
way faster, then Variant.

On Thu, Feb 9, 2012 at 3:12 PM, Alex_Dovhalalex_dov...@yahoo.com  wrote:

Sorry, my mistake. It's strange to have different 'n', but you measure speed
as 1000*n/time, so it's doesn't matter if n is 10 times bigger.





--
Bye,
Gor Gyolchanyan.



--
Graham St Jack



delve.tar.gz
Description: GNU Zip compressed data


Re: Suggestion for std.process upgrade

2011-12-12 Thread Graham St Jack

On 13/12/11 09:13, Steven Schveighoffer wrote:
On Mon, 12 Dec 2011 17:08:53 -0500, Bane 
branimir.milosavlje...@gmail.com wrote:


I have been playing with std.process (D2) lately, and have 2 
suggestions and more or less tested code if somebody other than my 
self have use for it.


One is shell() function (not mentioned in the docs, curious), I see 
it can be made more efficient on Windows. It executes shell command 
and returns standard output as string. Current implementation do it 
by piping stdout to temporary file on disk and reading that file 
back. Using CreateProccess Windows API it can do same job 3 times 
faster and remove need for temporary files and disk writes. I think 
that is beneficial gain for some applications.


Other is fork-exec implementation eg. starting a program using 
command line and detaching it from parent, so it continues to run 
after parent is dead. On Posix it is implemented using fork() and 
exec() calls, on Windows using CreateProcess.


There is a completely revamped version of std.process.  It is being 
held up right now because DMD on windows depends on DMC for it's C 
runtime, and DMC has issues supporting pipes.  I have recently opened 
a pull request for Walter to merge, I'm going to ping him about it 
right after 2.057 is released.


For more info, see the docs Lars posted here:

http://kyllingen.net/code/ltk/doc/process.html

Once the DMC issue is fixed, you should see this improvement getting 
much more attention.  It's very low hanging fruit.


-Steve


I took a look at the link, and it looks very nice.

I am currently trying to port an application over from Linux to Windows 
and the lack of wait(pid) is currently a blocker.


--
Graham St Jack



Re: Immutable Message Passing

2011-12-11 Thread Graham St Jack

On 11/12/11 12:59, Andrew Gough wrote:

On Mon, 05 Dec 2011 08:21:45 +0100
Jacob Carlborgd...@me.com  wrote:


On 2011-12-04 21:46, Andrew Wiley wrote:

On Sun, Dec 4, 2011 at 1:42 AM, Jonathan M
Davisjmdavisp...@gmx.com   wrote:

On Sunday, December 04, 2011 01:24:02 Andrew Wiley wrote:

This should work, right? I'm not just going crazy or something?

import std.concurrency;
import std.stdio;

class Bob {
}

void main() {
  auto tid = spawn(b);
  tid.send(new immutable(Bob)());
}

void b() {
  receive(
  (immutable(Bob) b) {
  writeln(got it);
  }
  );
}


I'm getting this from both GDC (trunk) and DMD (2.056 and trunk -
I can't seem to get 2.055 to run):
core.exception.AssertError@/usr/include/d/std/variant.d(286):
immutable(Bob)

Seems like some type conversion isn't working properly and
variant is flagging immutable types as not assignable?

Well, that particular assertion seems to be because of the
immutability. It seems that Variant can't handle it - the comment
with it being

// type is not assignable

But I'd have to go digging to see why on earth this is failing
(and that's assuming that it's not a compiler bug, since then it
would be completely out of my league). It _looks_ like it should
work.

- Jonathan M Davis

Actually, it looks like I am going crazy. I went back to dmd 2.052
(and every version in between), and this doesn't seem to have ever
worked.
However, not allowing message passing with immutable messages
eliminates one of the main use cases for immutable. I'll see if I
can find a workaround.

The actual issue is that once Variant finds a matching type, it
tries to assign `immutable(Bob) = immutable(Bob)` , which is
illegal. However, all it needs to do is assign a *reference* to an
immutable object. Unfortunately, we don't support that.
Incidentally, this makes a compelling argument for something like
immutable(Object) ref.

Have message passing ever worked for other than primitive types
(including strings) ?


It works for shared classes

Yes, but using shared classes brings its own problems that aren't easy 
to solve without something like tail shared/const/immutable.


--
Graham St Jack



Re: Why D const is annoying

2011-12-11 Thread Graham St Jack

On 11/12/11 06:55, Jonathan M Davis wrote:

On Saturday, December 10, 2011 05:45:11 bearophile wrote:

Timon Gehr:

Just slice the const array to get a range. The specialization for ranges
does not have the bug.

import std.algorithm;
void main() {

  const arr = [1, 2, 3];
  reduce!a*b(arr[]);   // It works.

}

Wasn't arr a range already?

Per isInputRange!(typeof(arr)), no. It has the right functions, but it can't
use them, because it's const. A const range is essentially useless, because
you can't iterate over it.

When a template is instantiated, it's instantiated on the exact types that
it's given. So, if you given a const or immutable array, it's going to
instantiate on that type, even though it _could_ theoretically instantiate
itself with a mutable array with const or immutable elements. And since, a
const or immutable array won't work as a range, the template instantiation
fails.

The range-based functions in std.array and std.string work with const and
immutable arrays simply because they are either coded specifically for arrays
or have specializations for them. You need a function which takes const(T)[]
rather than one which takes const T[]. std.array and std.string typically take
const(T)[] rather than const T[], whereas a more general range function is
taking R, which in the case above is determined to be const int[], which won't
work as a range.

It used to be that the slice of an array was the exact type of that array,
meaning Timon's solution wouldn't work without a cast, because the slice would
be just as const as the original. Fortunately, that has been changed, so now a
slice of a const or immutable array will have its elements be const or
immutable but not the slice itself. So, now const and immutable arrays are
like static arrays in that you need to slice them to use them with range-based
functions, but you can't use them directly with range-based functions.

A bigger problem is const or immutable ranges which are structs. Unless the
programmer who defined the range type managed to have an opSlice which returned
a version with const or immutable elements but where the range itself wasn't
const or immutable (i.e. a tail-const slice), then you can't even get slicing
to work. And even if templates were improved to the point that they would
instantiate const int[] as const(int)[] (which I expect is a change which will
never happen due to the difficulties in doing so), that wouldn't solve the
problem for ranges which aren't arrays.
Instead of an immutable struct trying to be a range, why not have it 
return a mutable range over its immutable elements? This would be 
analogous to slicing an immutable array.

Also, const and immutable ranges which aren't arrays which have no opSlice
will _never_ work, because there's no way to get a mutable slice of them to
operate on, so you're stuck with a const or immutable range.

Really what this means is that you need to slice const and immutable ranges
when you pass them to range-based functions, and then as long as they're
arrays or their opSlices have been defined properly, it'll work just fine.

If ranges had been designed more like slists (i.e. they have head and tail
rather than front and popFront), then they would have been inherently tail-
const and we wouldn't be having these problems. But that's less efficent,
because you have to copy the range every time that you want to remove an
element from it. Regardless, it's too late now. Ranges are too heavily used
with their current API for us to change it that drastically now.

- Jonathan M Davis



--
Graham St Jack



Re: Immutable Message Passing

2011-12-05 Thread Graham St Jack

On 05/12/11 18:48, Jacob Carlborg wrote:

On 2011-12-05 08:25, Graham St Jack wrote:


I always use arrays or structs. Until the tail-const thing (or something
like it) happens, classes don't seem to be viable in messages between
threads.


You can always serialize the object, if a copy is acceptable.

Sure - I was counting that as an array of bytes, and I sometimes resort 
to that too.


--
Graham St Jack



Re: Immutable Message Passing

2011-12-04 Thread Graham St Jack
My vote is for something like immutable(Object) ref, as Andrew suggested 
earlier. This would allow mutable references to immutable objects to be 
passed through a message channel without nasty typecasting.


std.typecons.Rebindable has always been an ugly hack that doesn't quite 
do the job. Certainly every attempt I have made to use it has ended 
unhappily, and I end up redesigning to not pass objects between threads.


What is the status of the immutable(Object) ref proposal? Is it on the 
list of things to do, or is it ruled out? If it is ruled out, then what 
is the superior proposal?



On 05/12/11 10:49, Timon Gehr wrote:

On 12/04/2011 11:32 PM, Andrew Wiley wrote:

On Sun, Dec 4, 2011 at 4:23 PM, Andrei Alexandrescu
seewebsiteforem...@erdani.org  wrote:

On 12/4/11 4:16 PM, Andrew Wiley wrote:


So it looks like right now, message passing is copying objects, which
seems very bad. Check this out:

import std.stdio;
import std.concurrency;

class Bob {
}

void main() {

auto tid = spawn(func);
auto bob = new shared(Bob)();
writeln(bob is currently at , cast(void*)(bob));



This is the address of the reference, not that of the object. Use
cast(void*)(bob).

Andrei


Ah, I am covered with shame.

In that case, no object copying is occurring, and I have message
passing for immutable objects working, although my current solution is
basically to check whether the object is immutable, and if so, memcpy
the reference. That breaks immutability, but only for the reference,
and I don't think there's any alternative unless we get tail
const/immutable into the language.

I'm guessing this is too hackish to get merged into std.variant?


You might want to have a look at std.typecons.Rebindable.



--
Graham St Jack



Re: Immutable Message Passing

2011-12-04 Thread Graham St Jack

On 05/12/11 17:51, Jacob Carlborg wrote:

On 2011-12-04 21:46, Andrew Wiley wrote:
On Sun, Dec 4, 2011 at 1:42 AM, Jonathan M 
Davisjmdavisp...@gmx.com  wrote:

On Sunday, December 04, 2011 01:24:02 Andrew Wiley wrote:

This should work, right? I'm not just going crazy or something?

import std.concurrency;
import std.stdio;

class Bob {
}

void main() {
 auto tid = spawn(b);
 tid.send(new immutable(Bob)());
}

void b() {
 receive(
 (immutable(Bob) b) {
 writeln(got it);
 }
 );
}


I'm getting this from both GDC (trunk) and DMD (2.056 and trunk - I
can't seem to get 2.055 to run):
core.exception.AssertError@/usr/include/d/std/variant.d(286): 
immutable(Bob)


Seems like some type conversion isn't working properly and variant is
flagging immutable types as not assignable?


Well, that particular assertion seems to be because of the 
immutability. It

seems that Variant can't handle it - the comment with it being

// type is not assignable

But I'd have to go digging to see why on earth this is failing (and 
that's
assuming that it's not a compiler bug, since then it would be 
completely out

of my league). It _looks_ like it should work.

- Jonathan M Davis


Actually, it looks like I am going crazy. I went back to dmd 2.052
(and every version in between), and this doesn't seem to have ever
worked.
However, not allowing message passing with immutable messages
eliminates one of the main use cases for immutable. I'll see if I can
find a workaround.

The actual issue is that once Variant finds a matching type, it tries
to assign `immutable(Bob) = immutable(Bob)` , which is illegal.
However, all it needs to do is assign a *reference* to an immutable
object. Unfortunately, we don't support that.
Incidentally, this makes a compelling argument for something like
immutable(Object) ref.


Have message passing ever worked for other than primitive types 
(including strings) ?


I always use arrays or structs. Until the tail-const thing (or something 
like it) happens, classes don't seem to be viable in messages between 
threads.


--
Graham St Jack



Re: Added --makedepend flag to rdmd

2011-06-06 Thread Graham St Jack

Thanks very much for this - I need it for the build tool I am working on.


On 06/06/11 01:18, Andrei Alexandrescu wrote:

I just added a --makedepend flag to rdmd:

https://github.com/D-Programming-Language/tools/commit/451ffed8ff985465a52124f7671494ac1d3744b4 



It instructs rdmd to simply print to stdout the name of the input file 
followed by a colon and then by the space-separated files that the 
input file depends on, directly or indirectly. Example:


// file test1.d;
import test2.d;

// file test2.d;
import test3.d, mylib.test4.d;

With this setup, assuming test3.d and test4.d contain no further 
non-system imports, the command:


rdmd --makedepend test1.d

will print

test1.d : ./test2.d ./mylib/test4.d ./test3.d

This flag is intended to be useful to larger-scale build tools that 
need to store and track module interdependencies. In the simplest use 
case, directing the output of rdmd --makedepend (for each of a 
project's root files) to a file and then including that file in a 
makefile will ensure that dependencies are properly maintained.



Cheers,

Andrei



--
Graham St Jack



Re: Message Passing and Shared Data

2011-04-11 Thread Graham St Jack

On 11/04/11 15:18, Jonathan M Davis wrote:

I'm working on an application that makes use of message passing to
separate things that need to be responsive from tasks that may take
some time, and I'm having trouble because my message passing
discipline isn't meshing with D's type system. I'm pretty much
following the contract that when I send a message from one thread to
another, the original thread doesn't store any references to the
message or what's in it, IE ownership is transferred. The receiving
thread may then send some of the same objects back after some
processing, but again, ownership is transferred.
This has the benefit that I avoid a lot of memory allocations, but it
means that right now, I'm constructing everything as shared, then
casting it away to populate the object, then sending the object, then
casting shared away again in the receiver, and so on.
The messages are generally passed around for things like requesting a
large chunk of data that takes a while to generate and receiving
objects from an IO thread that's decoding objects from sockets.

Any suggestions as to how I could avoid doing casts everywhere and/or
restore some sort of safety while avoiding having to reallocate every
object I mess with? I've tried fiddling with __gshared, but couldn't
figure out any way to use it with message passing.

There has been some talk of making it possible to do what you want to do with
a unique template or attribute, but it hasn't gone anywhere that I know of.
In particular, if it requires actual language changes, then it's unlikely to
change in D2. We might get some sort of template that solves the problem
though. I don't know.

For the moment, however, message passing only works with immutable values. End
of story. So, you have to do stuff like what you've been doing if you want to
get around it. Essentially, you either deal just with immutable values, cast
to and from immutable, or use shared. However, at the moment, there's no real
way to transfer ownership of an object between threads, so message passing
just doesn't do quite what you want to do. There may be a solution for it in
the future though.

- Jonathan M Davis


Slight correction - it works with a type that passes this test: 
!hasLocalAliasing!(T)

That means anything without references to non-immutable data.

In the example in question, it amounts to the same thing. The difference 
is that you can send plain-old-data too.


--
Graham St Jack



Re: a 'Shared libraries for Linux' question

2011-03-28 Thread Graham St Jack

On 29/03/11 15:35, Jonathan M Davis wrote:

On 2011-03-28 21:38, Long Chang wrote:

The shared lib support for Linux is very important for me .  I ask
people is there a schedule or plan once, but not get any responded .

I hope the somebody can tell us some information about this .

There's never really a schedule. Things get done when they get done.

Shared libraries are near the top of the todo list, but they aren't being work
on yet as far as I know. Walter has stated that he's currently focusing on
fixing bugs with regards to destructors and temporaries, and then he intends
to work on the issues with const (e.g.
http://d.puremagic.com/issues/show_bug.cgi?id=1824 ). There's a good chance
that shared libraries will be after that. But as to when exactly that'll be, I
don't know. They _are_ among the higher priorities, but there's a lot of
things that need to get done only and so much Walter to go around.

- Jonathan M Davis
That sounds fantastic. Those issues are the most troublesome for me, and 
have been for a long time.


--
Graham St Jack



Re: Strategies for resolving cyclic dependencies in static ctors

2011-03-27 Thread Graham St Jack
I sounds like we actually agree with each other on all the important 
points - its just the different starting positions made our 
near-identical ideas about testing to look different.


Thanks for the discussion.

--
Graham St Jack



Re: Strategies for resolving cyclic dependencies in static ctors

2011-03-24 Thread Graham St Jack

On 25/03/11 06:09, Steven Schveighoffer wrote:
On Thu, 24 Mar 2011 00:17:03 -0400, Graham St Jack 
graham.stj...@internode.on.net wrote:


Regarding unit tests - I have never been a fan of putting unit test 
code into the modules being tested because:
* Doing so introduces stacks of unnecessary imports, and bloats the 
module.


As Jonathan says, version(unittest) works.  No need to bloat 
unnecessarily.


Agreed. However, all the circularity problems pop up when you compile 
with -unittest.




* Executing the unittests happens during execution rather than during 
the build.


Compile-time code execution is not a good idea for unit tests.  It is 
always more secure and accurate to execute tests in the environment of 
the application, not the compiler.


I didn't say during compilation - the build tool I use executes the test 
programs automatically.




Besides, this is an implementation detail.  It is easily mitigated.  
For example, phobos' unit tests can be run simply by doing:


make -f posix.mak unittest

and it builds + runs all unit tests.  This can be viewed as part of 
the Build process.


The problem I have with this is that executing the tests requires a 
special build and run which is optional. It is the optional part that 
is the key problem. In my last workplace, I set up a big test suite that 
was optional, and by the time we got around to running it, so many tests 
were broken that it was way too difficult to maintain. In my current 
workplace, the tests are executed as part of the build process, so you 
discover regressions ASAP.




All unittests (as in the keyword) seem to have going for them is to 
be an aid to documentation.




The huge benefit of D's unit tests are that the test is physically 
close to the code it's testing.  This helps in debugging and managing 
updates.  When you update the code to fix a bug, the unit test is 
right there to modify as well.


I guess that was what I was alluding to as well. I certainly agree that 
having the tests that close is handy for users of a module. The extra 
point you make is that the unittest approach is also easier for the 
maintainer, which is fair enough.




The whole point of unittests are, if they are not easy to do and 
conveniently located, people won't do them.  You may have a really 
good system and good coding practices that allows you to implement 
tests the way you do.  But I typically will forget to update tests 
when I'm updating code.  It's much simpler if I can just add a new 
line right where I'm fixing the code.


In practice I find that unit tests are often big and complex, and they 
deserve to be separate programs in their own right. The main exception 
to this is low-level libraries (like phobos?).




What I do instead is put unit tests into separate modules, and use a 
custom build system that compiles, links AND executes the unit test 
modules (when out of date of course). The build fails if a test does 
not pass.


The separation of the test from the code under test has plenty of 
advantages and no down-side that I can see - assuming you use a build 
system that understands the idea. Some of the advantages are:

* No code-bloat or unnecessary imports.


Not a real problem with version(unittest).


* Much easier to manage inter-module dependencies.


Not sure what you mean here.


I mean that the tests typically have to import way more modules than the 
code under test, and separating them is a key step in eliminating 
circular imports.




* The tests can be fairly elaborate, and can serve as well-documented 
examples of how to use the code under test.


This is not an against for unit tests, they can be this way as well.  
Unit testing phobos takes probably a minute on my system, including 
building the files.  They are as complex as they need to be.


Conceded - it doesn't matter where the tests are, they can be as big as 
they need to be.


As for the time tests take, an important advantage of my approach is 
that the test programs only execute if their test-passed file is out of 
date. This means that in a typical build, very few (often 0 or 1) tests 
have to be run, and doing so usually adds way less than a second to the 
build time. After every single build (even in release mode), you know 
for sure that all the tests pass, and it doesn't cost you any time or 
effort.




* Since they only execute during the build, and even then only when 
out of date, they can afford to be more complete tests (ie use plenty 
of cpu time)


IMO unit tests should not be run along with the full application.  I'd 
suggest a simple unit test blank main function.  I think even dmd (or 
rdmd?) will do this for you.


There is no requirement to also run your application when running unit 
tests.


That is my point exactly. I don't run tests as part of the application - 
the tests are separate utilities intended to be run automatically by the 
build tool. They can also be run manually to assist in debugging when 
something goes

Re: Strategies for resolving cyclic dependencies in static ctors

2011-03-23 Thread Graham St Jack
Regarding unit tests - I have never been a fan of putting unit test code 
into the modules being tested because:

* Doing so introduces stacks of unnecessary imports, and bloats the module.
* Executing the unittests happens during execution rather than during 
the build.


All unittests (as in the keyword) seem to have going for them is to be 
an aid to documentation.


What I do instead is put unit tests into separate modules, and use a 
custom build system that compiles, links AND executes the unit test 
modules (when out of date of course). The build fails if a test does not 
pass.


The separation of the test from the code under test has plenty of 
advantages and no down-side that I can see - assuming you use a build 
system that understands the idea. Some of the advantages are:

* No code-bloat or unnecessary imports.
* Much easier to manage inter-module dependencies.
* The tests can be fairly elaborate, and can serve as well-documented 
examples of how to use the code under test.
* Since they only execute during the build, and even then only when out 
of date, they can afford to be more complete tests (ie use plenty of cpu 
time)
* If the code builds, you know all the unit tests pass. No need for a 
special unittest build and manual running of assorted programs to see if 
the tests pass.

* No need for special builds with -unittest turned on.


--
Graham St Jack



Re: Strategies for resolving cyclic dependencies in static ctors

2011-03-23 Thread Graham St Jack

On 24/03/11 15:19, Jonathan M Davis wrote:

Regarding unit tests - I have never been a fan of putting unit test code
into the modules being tested because:
* Doing so introduces stacks of unnecessary imports, and bloats the module.
* Executing the unittests happens during execution rather than during
the build.

All unittests (as in the keyword) seem to have going for them is to be
an aid to documentation.

What I do instead is put unit tests into separate modules, and use a
custom build system that compiles, links AND executes the unit test
modules (when out of date of course). The build fails if a test does not
pass.

The separation of the test from the code under test has plenty of
advantages and no down-side that I can see - assuming you use a build
system that understands the idea. Some of the advantages are:
* No code-bloat or unnecessary imports.
* Much easier to manage inter-module dependencies.
* The tests can be fairly elaborate, and can serve as well-documented
examples of how to use the code under test.
* Since they only execute during the build, and even then only when out
of date, they can afford to be more complete tests (ie use plenty of cpu
time)
* If the code builds, you know all the unit tests pass. No need for a
special unittest build and manual running of assorted programs to see if
the tests pass.
* No need for special builds with -unittest turned on.

Obviously, it wouldn't resolve all of your concerns, but I would point out
that you can use version(unittest) to enclose stuff that's only supposed to be
in the unit tests build. And that includes using version(unittest) on imports,
avoiding having to import stuff which is only needed for unit tests during
normal builds.

- Jonathan M Davis

That is a good point, but as you say, it doesn't address all the concerns.

I would be interested to hear some success stories for the 
unittest-keyword approach. So far I can't see any up-side.


--
Graham St Jack



Re: Strategies for resolving cyclic dependencies in static ctors

2011-03-22 Thread Graham St Jack

On 23/03/11 03:41, Steven Schveighoffer wrote:

On Mon, 21 Mar 2011 20:12:55 -0400, Nick Sabalausky a@a.a wrote:


I'm intending this thread as somewhat of a roundtable-like discussion.
Hopefully we can come up with good material for a short article on 
Wiki4D,

or maybe the D website, or wherever.

The scenario: A coder is writing some D, compiles, runs and gets a 
Cyclic
dependency in static ctors error. Crap! A pain for experienced D 
users, and
very bad PR for new D users. (Hopefully we'll eventually get some 
sort of
solution for this, but in the meantime D users just have to deal with 
it.)


The question: What now? What strategies do people find useful for 
dealing

with this? Any specific first steps to take? Best practices? Etc.


What one can try is to factor out the initialization code into a 
separate module.  Essentially if you have:


module a;
import f : someFunction;
import b; // conflicts because of circular dependencies

int aglobal;

static this()
{
  aglobal = someFunction();
}

You can do something like:

module a_static;
import f : someFunction;

int aglobal;

static this()
{
   aglobal = someFunction();
}

in a.d:
module a;
public import a_static;
import b;

Of course, there can be reprecussions -- you may need to have aglobal 
declared in a.d.  In those cases, one can try to hide the cycle as Max 
Samuckha stated, but I'd rather see a compiler option than these kinds 
of workarounds.  The workarounds can be unobvious, but can be just as 
dangerous.


-Steve


My own solution to this problem is to never have circular imports at 
all. The build system I use prohibits them, so any careless introduction 
of a circularity is spotted immediately and I refactor the code to 
eliminate the circularity. I have never come across a valid need for 
circularities, and have never had any trouble eliminating any that creep in.


Avoiding circularities has plenty of advantages, like progressive 
development, testing and integration. On bigger projects these 
advantages are very important, and even on small ones they are useful.


--
Graham St Jack



Re: What To Do About Shared?

2011-03-22 Thread Graham St Jack

On 23/03/11 11:08, dsimcha wrote:
Some discussions about std.parallelism have prompted an examination of 
how far D's guarantees against low level data races should extend and 
how safety and practicality should be balanced.  On the one hand, 
coarse-grained multithreading with hard guarantees against low-level 
races is a great thing if it's flexible enough to do what you need it to.


On the other hand, not everything is implementable (at least not 
efficiently or easily) in such a paradigm.  D is a systems language 
and should not force people who want unchecked shared state 
multithreading to either do without it for fight the type system every 
inch of the way (by casting all over the place) to get it.


I've come up with the following proposal, which is implicitly used in 
the design of std.parallelism, but which I think should be made explicit.


1.  All @safe code must be statically checkable and provably free from 
low level data races provided that all @trusted code it calls is 
correctly implemented.  It may not cast away shared, etc.


2.  All @trusted code must guarantee to its clients that calling such 
code from @safe code will not result in low level data races.


3.  All modules that deal with multithreading must document either that:

a.  They will use the type system to guarantee that low-level data 
races can't happen.


b.  They will share state freely.

c.  They will mostly share state freely, but will make guarantees 
about some specific subset.


std.concurrency would be in category a.  core.thread would be in 
category b.  std.parallelism would be in category c.


All code that only uses modules from category a, does not cast away 
shared and does not use __gshared variables can be guaranteed free 
from low level data races even if it is not @safe.


If you want hard guarantees about low level data races, these can be 
achieved with a very small amount of discipline:  Only use modules 
from category a or only use @safe code.  This is easily checkable.  
Using modules from category b or modules from category c in non-@safe 
code should be considered equivalent to casting away shared:  You may 
do so, but you're on your own when it comes to thread safety and you 
may not do it in @safe code.


Sounds good in principal.

I assume that category a code could be @trusted, and that category b and 
c must not be @trusted.


I agree that trying to use the language to discriminate between category 
b and c would be too tricky, especially when you consider the subtleties 
of what is shared and what is not. Documentation is the only viable 
option there.


Are these static checks feasible, and if so, what are the chances of 
getting them into the language anytime soon?


--
Graham St Jack



Re: Strategies for resolving cyclic dependencies in static ctors

2011-03-22 Thread Graham St Jack

On 23/03/11 15:12, Nick Sabalausky wrote:

Graham St Jackgraham.stj...@internode.on.net  wrote in message
news:imbai9$2jb9$1...@digitalmars.com...

My own solution to this problem is to never have circular imports at
all. The build system I use prohibits them, so any careless introduction
of a circularity is spotted immediately and I refactor the code to
eliminate the circularity. I have never come across a valid need for
circularities, and have never had any trouble eliminating any that creep
in.

Avoiding circularities has plenty of advantages, like progressive
development, testing and integration. On bigger projects these advantages
are very important, and even on small ones they are useful.


That's certainly good in many cases, but I find there are many times when a
one-way dependency graph just doesn't fit the given problem and causes
more trouble than it solves. You often end up needing to re-invent the wheel
to avoid a dependency, or split/arrange/merge modules in confusing
unintuitive ways that have more to do with implementation detail than
high-level purpose.



I'm happy to admit that these cases could come up, but I have never yet 
seen one where the design wasn't improved by removing the circularity.



--
Graham St Jack



Re: Proposal for std.path replacement

2011-03-03 Thread Graham St Jack

On 04/03/11 02:59, Lars T. Kyllingstad wrote:

As mentioned in the std.path.getName(): Screwy by design? thread, I
started working on a rewrite of std.path a long time ago, but I got
sidetracked by other things.  The recent discussion got me working on it
again, and it turned out there wasn't that much left to be done.

So here it is, please comment:

 http://kyllingen.net/code/ltk/doc/path.html
 https://github.com/kyllingstad/ltk/blob/master/ltk/path.d

Features:

- Most functions work with all string types, i.e. all permutations of
mutable/const/immutable(char/wchar/dchar)[].  Notable exceptions are
toAbsolute() and toCanonical, because they rely on std.file.getcwd()
which returns an immutable(char)[].

- Correct behaviour in corner cases that aren't covered by the current
std.path.  See the other thread for some examples, or take a look at the
unittests for a more complete picture.

- Saner naming scheme.  (Still not set in stone, of course.)

-Lars


I like it. It certainly looks a lot cleaner than the current std.path.

I am interested in why you chose to use templates to allow not only 
char, dchar and wchar arrays, but also const, mutable, and immutable. My 
first instinct would be to use non-templated functions that take const 
char[].


--
Graham St Jack



Re: Proposal for std.path replacement

2011-03-03 Thread Graham St Jack

On 04/03/11 12:34, Bekenn wrote:

On 3/3/11 3:30 PM, Graham St Jack wrote:
My first instinct would be to use non-templated functions that take 
const

char[].



Please don't ever restrict encodings like that.  As much as possible, 
libraries should seek to be encoding agnostic (though I'm all for 
const-qualifying parameters).  This is one area where I feel the 
standard library severely lacks at present.


As a Windows developer, I prefer to use wchar strings by default and 
use only the W versions of the Windows API functions, because the A 
versions severely limit functionality.  Only the W versions have full 
support for Unicode; the A versions are entirely dependent on the 
current (8-bit) code page.  This means no support for UNC paths or 
paths longer than 260 characters, and also means that international 
characters commonly end up completely garbled.  Good practice in 
Windows is to consider the A versions deprecated and avoid them like 
the plague.


Ok, I don't mind supporting wchar and dchar in addition to char, 
especially if Windows insists on using them.


My main issue here is with the constness of the parameters. I think the 
correct parameter to pass is const C[]. This has the advantages of:

* Accepting both mutable and immutable data.
* Declares that the function won't mutate the data.
* Declares that the function doesn't expect the data to be immutable.

It would be even better to use const scope char[], declaring that a 
reference won't be kept, but it seems that scope in this context is 
deprecated.


Once upon a time in meant const scope. Does anyone know what it means now?

--
Graham St Jack



Re: dmd 1.067 and 2.052 release

2011-02-21 Thread Graham St Jack

On 21/02/11 16:14, Michel Fortin wrote:
On 2011-02-20 20:21:20 -0500, Graham St Jack 
graham.stj...@internode.on.net said:


In particular, are there any plans to re-examine the tail-const issue 
in light of the compiler patch proposed by Michel Fortin in his post: 
const(Object)ref is here! back in December?


Note that there's now a pull request for that:
https://github.com/D-Programming-Language/dmd/pull/3

And if someone wants to test it, just download and compile the 
const-object-ref branch of my dmd fork:

https://github.com/michelf/dmd/tree/const-object-ref

I'm currently waiting for feedback from Walter about this (and 
possibly others who dare to test it before it's in the mainline) 
before putting more work on it.



Excellent - hopefully Walter will like it. I will have a go at compiling 
your branch and trying it out, but my use cases aren't all that stressful.


--
Graham St Jack



Re: dmd 1.067 and 2.052 release

2011-02-20 Thread Graham St Jack

Fantastic news! Well done once again to the whole team.

Now that the 64-bit bugbear is in the bag (along with a big pile of 
bugs), what is next? Is there a list somewhere detailing the planned 
language/toolchain changes that will make it into D2? Are we converging 
on a stable release of the language anytime soon?


In particular, are there any plans to re-examine the tail-const issue in 
light of the compiler patch proposed by Michel Fortin in his post: 
const(Object)ref is here! back in December?


Some other issues I assume are still in flux (and can remember) are:
* Tweaks to usability of const/immutable/shared.
* Tweaks to usability of nothrow, pure, etc.
* Rollout of const, nothrow, pure, etc thoughout phobos.
* Fate of the delete keyword.
* Fate of the scope keyword used in object declaration and function 
parameters.
* Meaning of in keyword for function parameters. Is it just const, and 
if so, why not just use const?


I don't have (much) of a personal agenda here - I just want the rough 
edges smoothed off and a stable language.



--

Graham St Jack



Re: How will we fix opEquals?

2011-02-10 Thread Graham St Jack


This isn't really true.  If you make opEquals const, then anything 
opEquals calls must be const.  Inevitably, you need to make a lot of 
your object const, which then goes viral to things that object uses, etc.


On the other hand, I don't think opt-in const is that worthy a goal.  
Things that are const, should be const.


-Steve


I totally agree - we need to take the plunge and roll const out through 
phobos. If const (and immutable too for that matter) is broken in subtle 
ways, then it needs to be fixed and then embraced.


--
Graham St Jack



Re: How will we fix opEquals?

2011-02-10 Thread Graham St Jack

Vote++

--
Graham St Jack



Re: findSkip signature

2011-01-17 Thread Graham St Jack

On 18/01/11 08:04, Andrei Alexandrescu wrote:

On 1/17/11 3:21 PM, Ali Çehreli wrote:

Andrei Alexandrescu wrote:

I just added a useful function to Phobos: findSkip. Refer to

http://d-programming-language.org/cutting-edge/phobos/std_algorithm.html#findSkip 




and

http://www.dsource.org/projects/phobos/changeset/2339

I'm unsure about the signature. Currently the function returns
Tuple!(R1, balance, bool, found), i.e. the balance of the range
being searched and a Boolean telling whether or not the other range
was found. The Boolean is necessary because returning an empty range
is ambiguous - did you find the needle at the very end of the
haystack, or not at all?

I think a signature that's easier to use is:

bool findSkip(alias pred = a == b, R1, R2)(ref R1 haystack, R2 
needle);


i.e. the haystack is passed by reference and modified if the find was
successful. This is in keep with skipOver's signature, but not in keep
with find's signature.

Opinions?


Andrei


I am not sure where findSkip is useful but can we assume that the caller
is not interested in whether it was found or not?

If the callers are interested, they should have the option of calling
find and skip separately. If they are always interested, then find and
skip should not be merged together.


findSkip is useful in parsing. One simple case in which it was useful 
was count() that counts how many times a forward range occurs in 
another. You can't do that with find(). (Try it!)


I made the executive decision to pass by reference and return a bool.

vote++


http://d-programming-language.org/cutting-edge/phobos/std_algorithm.html#findSkip 




Andrei



--
Graham St Jack



Re: Portability bug in integral conversion

2011-01-16 Thread Graham St Jack

On 16/01/11 08:52, Andrei Alexandrescu wrote:
We've spent a lot of time trying to improve the behavior of integral 
types in D. For the most part, we succeeded, but the success was 
partial. There was some hope with the polysemy notion, but it 
ultimately was abandoned because it was deemed too difficult to 
implement for its benefits, which were considered solving a minor 
annoyance. I was sorry to see it go, and I'm glad that now its day of 
reckoning has come.


Some of the 32-64 portability bugs have come in the following form:

char * p;
uint a, b;
...
p += a - b;

On 32 bits, the code works even if a  b: the difference will become a 
large unsigned number, which is then converted to a size_t (which is a 
no-op since size_t is uint) and added to p. The pointer itself is a 
32-bit quantity. Due to two's complement properties, the addition has 
the same result regardless of the signedness of its operands.


On 64-bits, the same code has different behavior. The difference a - b 
becomes a large unsigned number (say e.g. 4 billion), which is then 
converted to a 64-bit size_t. After conversion the sign is not 
extended - so we end up with the number 4 billion on 64-bit. That is 
added to a 64-bit pointer yielding an incorrect value. For the 
wraparound to work, the 32-bit uint should have been sign-extended to 
64 bit.


To fix this problem, one possibility is to mark statically every 
result of one of uint-uint, uint+int, uint-int as non-extensible, 
i.e. as impossible to implicitly extend to a 64-bit value. That would 
force the user to insert a cast appropriately.


Thoughts? Ideas?


Andrei
It seems to me that the real problem here is that it isn't meaningful to 
perform (a-b) on unsigned integers when (ab). Attempting to clean up 
the resultant mess is really papering over the problem. How about a 
runtime error instead, much like dividing by 0?



--
Graham St Jack



Re: Portability bug in integral conversion

2011-01-16 Thread Graham St Jack

On 17/01/11 10:39, Andrei Alexandrescu wrote:

On 1/16/11 5:24 PM, Graham St Jack wrote:

On 16/01/11 08:52, Andrei Alexandrescu wrote:

We've spent a lot of time trying to improve the behavior of integral
types in D. For the most part, we succeeded, but the success was
partial. There was some hope with the polysemy notion, but it
ultimately was abandoned because it was deemed too difficult to
implement for its benefits, which were considered solving a minor
annoyance. I was sorry to see it go, and I'm glad that now its day of
reckoning has come.

Some of the 32-64 portability bugs have come in the following form:

char * p;
uint a, b;
...
p += a - b;

On 32 bits, the code works even if a  b: the difference will become a
large unsigned number, which is then converted to a size_t (which is a
no-op since size_t is uint) and added to p. The pointer itself is a
32-bit quantity. Due to two's complement properties, the addition has
the same result regardless of the signedness of its operands.

On 64-bits, the same code has different behavior. The difference a - b
becomes a large unsigned number (say e.g. 4 billion), which is then
converted to a 64-bit size_t. After conversion the sign is not
extended - so we end up with the number 4 billion on 64-bit. That is
added to a 64-bit pointer yielding an incorrect value. For the
wraparound to work, the 32-bit uint should have been sign-extended to
64 bit.

To fix this problem, one possibility is to mark statically every
result of one of uint-uint, uint+int, uint-int as non-extensible,
i.e. as impossible to implicitly extend to a 64-bit value. That would
force the user to insert a cast appropriately.

Thoughts? Ideas?


Andrei

It seems to me that the real problem here is that it isn't meaningful to
perform (a-b) on unsigned integers when (ab). Attempting to clean up
the resultant mess is really papering over the problem. How about a
runtime error instead, much like dividing by 0?


That's too inefficient.

Andrei


If that is the case, then a static check like you are suggesting seems 
like a good way to go. Sure it will be annoying, but it will pick up a 
lot of bugs.


This particular problem is one that bights me from time to time because 
I tend to use uints wherever it isn't meaningful to have negative 
values. It is great until I need to do a subtraction, when I sometimes 
forget to check which is greater. Would the check you have in mind 
statically check the following as ok?


where a and b are uints and ptr is a pointer:

if (a  b) {
ptr += (a-b);
}


--
Graham St Jack



Re: Portability bug in integral conversion

2011-01-16 Thread Graham St Jack

On 17/01/11 13:30, Andrei Alexandrescu wrote:

On 1/16/11 7:51 PM, Graham St Jack wrote:

On 17/01/11 10:39, Andrei Alexandrescu wrote:

On 1/16/11 5:24 PM, Graham St Jack wrote:

On 16/01/11 08:52, Andrei Alexandrescu wrote:

We've spent a lot of time trying to improve the behavior of integral
types in D. For the most part, we succeeded, but the success was
partial. There was some hope with the polysemy notion, but it
ultimately was abandoned because it was deemed too difficult to
implement for its benefits, which were considered solving a minor
annoyance. I was sorry to see it go, and I'm glad that now its day of
reckoning has come.

Some of the 32-64 portability bugs have come in the following form:

char * p;
uint a, b;
...
p += a - b;

On 32 bits, the code works even if a  b: the difference will 
become a
large unsigned number, which is then converted to a size_t (which 
is a

no-op since size_t is uint) and added to p. The pointer itself is a
32-bit quantity. Due to two's complement properties, the addition has
the same result regardless of the signedness of its operands.

On 64-bits, the same code has different behavior. The difference a 
- b

becomes a large unsigned number (say e.g. 4 billion), which is then
converted to a 64-bit size_t. After conversion the sign is not
extended - so we end up with the number 4 billion on 64-bit. That is
added to a 64-bit pointer yielding an incorrect value. For the
wraparound to work, the 32-bit uint should have been sign-extended to
64 bit.

To fix this problem, one possibility is to mark statically every
result of one of uint-uint, uint+int, uint-int as non-extensible,
i.e. as impossible to implicitly extend to a 64-bit value. That would
force the user to insert a cast appropriately.

Thoughts? Ideas?


Andrei
It seems to me that the real problem here is that it isn't 
meaningful to

perform (a-b) on unsigned integers when (ab). Attempting to clean up
the resultant mess is really papering over the problem. How about a
runtime error instead, much like dividing by 0?


That's too inefficient.

Andrei


If that is the case, then a static check like you are suggesting seems
like a good way to go. Sure it will be annoying, but it will pick up a
lot of bugs.

This particular problem is one that bights me from time to time because
I tend to use uints wherever it isn't meaningful to have negative
values. It is great until I need to do a subtraction, when I sometimes
forget to check which is greater. Would the check you have in mind
statically check the following as ok?

where a and b are uints and ptr is a pointer:

if (a  b) {
ptr += (a-b);
}


That would require flow analysis. I'm not sure we want to embark on 
that ship. In certain situations value range propagation could take 
care of it.


Andrei



My fear is that if a cast is always required, people will just put one 
in out of habit and we are no better off (just like exception-swallowing).


Is the cost of run-time checking really prohibitive? Correct code should 
have some checking anyway. Maybe providing phobos functions to perform 
various correct-usage operations with run-time checks like in my code 
fragment above would by useful. They could do the cast, and most of the 
annoyance factor would be dealt with. A trivial example:


int difference(uint a, uint b) {
  if (a = b) {
return cast(int) a-b;
  }
  else {
return -(cast(int) b-a);
  }
}

--
Graham St Jack



Re: Portability bug in integral conversion

2011-01-16 Thread Graham St Jack

On 17/01/11 14:16, Jonathan M Davis wrote:

On Sunday 16 January 2011 19:38:55 Andrei Alexandrescu wrote:

On 1/16/11 9:32 PM, Graham St Jack wrote:

Is the cost of run-time checking really prohibitive?

Yes. There is no question about that. This is not negotiable.

Well, since it would mean checking a condition every time that you did
arithmetic, that would likely _at least_ double the cost of doing any
arithmetic. And particularly since arithmetic is such a basic operation that
_everything else_ relies on, that could get really expensive, really fast.

Yeah. I don't think that that's negotiable. Absolutely best case, I could see
adding a compiler flag to enable it for debugging purposes, but it would
definitely be expensive to do such checks and would be totally unacceptable in
the release build of a systems programming language.

- Jonathan M Davis
Yes, I agree that checking all the time would be too expensive. What I 
meant was that we could provide functions that could do appropriate 
checking when it is needed.


Andrei didn't like the functions idea, suggesting types that do 
policy-based checking, which I am happy with.


--
Graham St Jack



Re: New syntax for string mixins

2010-12-16 Thread Graham St Jack


I've attached a part of how concurrency.d could look like translated 
to my suggested syntax. It probably contains a lot of errors because 
did a quick translation and I had some trouble understanding the mixins.


Yes, even I couldn't understand them even a week later. Maintenance is a 
real problem.


My initial reaction is that the proposed syntax helps a bit, but isn't 
really a game-changer. I will let you know if I change my mind on closer 
inspection.


--
Graham St Jack



Re: New syntax for string mixins

2010-12-14 Thread Graham St Jack

On 14/12/10 20:33, Vladimir Panteleev wrote:

On Tue, 14 Dec 2010 09:30:46 +0200, Graham St Jack
graham.stj...@internode.on.net wrote:


There is of course the worry that it could get so easy that everyone
starts doing it, and we have (relatively) impenetrable code everywhere
instead of just deep in the bowels of framework libraries.


TBH, I'm more excited by AST macros which I understood are planned for
D3, as mentioned here:
http://s3.amazonaws.com/dconf2007/WalterAndrei.pdf
They seem to promise the power of mixins, but without the mess.



I took a look at the pdf, but couldn't see how the AST macros could come
close to the kinds of things that are possible (but difficult) with 
mixins. Is there more information somewhere?


Jacob, I can see how your proposed syntax would make simple mixins 
easier and clearer, but how would it do something more complex?


For example taking a classname and a bunch of field types and names, and 
turning it into a class definition complete with constructor from field 
values, constructor from an input stream, a method to write to an output 
stream, and const getters. Or maybe std.typecons.AutoImplement.



--
Graham St Jack


Re: New syntax for string mixins

2010-12-14 Thread Graham St Jack



I don't know, do you have an example ?


For example taking a classname and a bunch of field types and names, and
turning it into a class definition complete with constructor from field
values, constructor from an input stream, a method to write to an output
stream, and const getters. Or maybe std.typecons.AutoImplement.


Could you post an example of how that mixin would be used and the code 
it would generate then I can see if I can translate it to my syntax. 
AutoImplement seems to just contain template mixins which is something 
else.




I have attached my concurrency framework, which relies heavily on 
mixins, plus its unit test to show how it is used. I haven't included 
the various dependencies because I assume you just want the example 
code. Let me know if you want something buildable, or perhaps something 
more cut-down.


What the code-generating template does is to create from something like 
this (you can have any number of Messages in a Protocol):



alias Protocol!(Requests,Message!(job,string, name)).code 
jobCode;

mixin(jobCode);


this code:


class Requests {
struct jobMsg {
string name;
this(string name) {
 this.name = name;
}
void read(InStream stream) {
 name = stream.get!string;
}
void write(OutStream stream) {
stream(name);
}
}
struct Message {
uint kind;
union {
jobMsg job;
}
this(ref jobMsg msg) {
kind = 0;
job = msg;
}
this(InStream stream) {
kind = stream.get!uint;
switch(kind) {
case 0: job.read(stream); break;
default: assert(0, Cannot read unsupported message kind);
}
}
void write(OutStream stream) {
stream(kind);
switch(kind) {
case 0: job.write(stream); break;
default: assert(0, Cannot write unsupported message 
kind);

}
}
}
private alias Channel!(Message) _Chan;
private alias shared _Chan Chan;

private Chan channel;
this() { channel = new Chan(); }
ChannelSelectable newSelectable() { return channel.newSelectable(); }
void finalize() { channel.finalize; }

interface IHandler {
void job(string name);
}
void job(string name) {
channel.add(Message(jobMsg(name)));
}
void receive(IHandler handler) {
auto message = channel.remove;
switch (message.kind) {
case 0: handler.job(message.job.name); break;
default: assert(0, Cannot dispatch unsupported message kind);
}
}
}



I use this for inter-thread communications, and I use the discriminated 
union to pass messages between processes. The manual mixin after the 
alias is a debugging aid - the compiler errors when doing mixins aren't 
helpful at all. I case you are wondering why I did all this, it was 
partly a learning experience, but mostly an attempt to do something 
properly thread-safe (!hasAliasing), using shared, const and immutable 
properly.


--
Graham St Jack

module bedrock.maxim.concurrency;

public import bedrock.maxim.io;
public import bedrock.maxim.stream;

import bedrock.maxim.logging;

import std.algorithm;
import std.stdio;
import std.conv;
import std.traits;
import std.typecons;
import std.typetuple;

import core.thread;

import core.stdc.stdlib;
import core.stdc.errno;
import core.stdc.config;

import core.sys.posix.pthread;
import core.sys.posix.signal;

static import linux = std.c.linux.linux;


//
// Provides a message-passing concurrency implementation.
// * Messages cannot contain references to mutable data.
// * Message queues (Channels) are explicitly created and passed to threads as
//   arguments to spawn().
// * Channels are synchronized (and thus shared).
// * The types of messages a Channel supports are well-defined.
// * Messages are processed in order.
// * Multiple threads can receive from the same Channel.
// * Channels have an internal pipe that can be used in a Selector to allow
//   a thread to receive input from multiple Channels and file-descriptor devices
//   such as sockets and pipes.
// * There is no automatic thread-termination behaviour.
//
// TODO - prevent non-shared aliased data from being passed to spawn().
// TODO - gathering non-fatal signals via signalfd, putting info on a Channel.
//


//-
// Condition - Adapted from core.sync.condition to be linux-specific,
// use an object's monitor and to be shared.
//-

public class ConditionException : Exception {
this(string text) { super(text); }
}

// clock_gettime definitions copied from commented-out and scattered
// definitions in druntime
private {
enum int CLOCK_REALTIME = 0;
enum int TIMER_ABSTIME  = 0x01

Re: New syntax for string mixins

2010-12-13 Thread Graham St Jack
I have done a fair bit of mixin coding using recursive templates 
(inspired by std.typecons). It was an amazing taste of what you can do 
in D, and I am delighted with the result - HEAPS of boiler-plate coding 
vanished before my eyes. However, the template code is virtually 
impossible to understand.


What you are suggesting here seems to be a way to dramatically reduce 
the complexity of code that generates source-code and mixes it in. I 
think something like that is needed before this mind-bogglingly powerful 
feature of D can realise its potential.


There is of course the worry that it could get so easy that everyone 
starts doing it, and we have (relatively) impenetrable code everywhere 
instead of just deep in the bowels of framework libraries.



On 14/12/10 07:07, Jacob Carlborg wrote:
This is an idea I've been thinking of for a while, it's not a really 
suggestion (at least not yet) I just wanted to here what people think 
about it.


If we take a step back and look at what string mixins actually do or 
rather what they're used for, that would be: inserting a piece/block 
of code where the mixin expression is used. If we then take a look at 
how a block of code is represented in D (how you store it in variables 
and how you pass it around). It's not as a string which is used by the 
mixin expression, instead delegates are used to represent a block of 
code in D that can be passed around. Therefore this is my idea:


Add a new mixin operator @ (1). When that operator is put in front 
of a function call it would behave as a string mixin. The function 
that is called needs to be CTFE and return a delegate or an array of 
delegates:


class Foo
{
@get_set(int, bar);
}

The above code would be the same as the following code:

class Foo
{
mixin(get_set(int, bar));
}

If we now move to the declaration of get_set this is how it could 
look like:


void delegate () get_set (string type, string name)
{
return
{
@type _...@name;

@type @name ()
{
return _...@name;
}

@type @name (@type @name)
{
return _...@name = @name;
}
};
}

In the above code when @ is used in the delegate literal it 
basically behaves like string interpolation, so @type would be 
replaced with the content of the type variable (2).


When the get_set function is called with the mixin symbol the 
content of the returned delegate is inserted where the call is made. 
If the function returns an array of delegates then the array would be 
unfolded and the content of all the delegates would be inserted.




Taking it one step further:

Allow the mixin syntax to be placed in front of most of the 
declarations and drop the need for string literals, commas and 
parentheses, basically allowing the following syntax:


class Foo
{
@get_set int bar;
}

Would be translated into this:

class Foo
{
@get_set!(int)(bar);
}

Maybe one could do something like this as well:

@singleton class Foo
{

}

void delegate () singleton (string name, void delegate () classBody)
{
return { // a simple singleton implementation
class @name
{
static @name instance;

static this ()
{
instance = new @name;
}

private this () {}

@classBody;
}
};
}

Above, in the last example, @classBody would insert the content of the 
delegate, basically the class body.


1. I will use @ in this example because I think it looks good but it 
would probably conflict with @nothrow, @property and others.


2. I have no idea if this usage of the mixin symbol, @, will 
conflict with the first usage.





--
Graham St Jack



Re: const(Object)ref is here!

2010-12-06 Thread Graham St Jack

On 07/12/10 05:51, Steven Schveighoffer wrote:
On Mon, 06 Dec 2010 14:04:43 -0500, Jonathan M Davis 
jmdavisp...@gmx.com wrote:



On Monday, December 06, 2010 07:37:27 Steven Schveighoffer wrote:


It should be relatively painless.  Just change the signatures of the 
base

functions, and fix any compile errors.


And watch all the code break... I'll definitely welcome the change 
(it's probably
the first bug that I voted on in bugzilla), but there will be tons of 
code broken
by it, since you just _know_ that a lot of user code doesn't bother 
to make
toString() and its friends const. It's still a change that needs to 
be made

though. Being unable to properly compare const and immutable objects is
crippling. Of course, it would be more of an issue if it were easier 
to actually
create immutable objects which are classes rather than strcuts, but 
that's a

separate issue.


Yes, one of the issues is that const has a viral effect.  If you 
ignore const, none of your functions are const.  So if you use 
functions inside opEquals, those have to be marked as const, and so on.


But there are very few circumstances where opEquals needs to be marked 
as mutable.  If that is the case, there is something broken with your 
code (and you should fix it) or there's something wrong with code you 
use (and you'll have to insert casts to deal with it for now).  In a 
very small number of circumstances, non-const opEquals can be 
beneficial (such as caching data that is expensive to calculate).  We 
need to find another way to deal with that (I suggest having logical 
const, but that's not a popular idea with Walter :).  But it shouldn't 
detract from the requirements.  You can always circumvent if you need 
special cases.  I'd rather start from a solid const-supporting 
position and add holes where they make sense then start from a base 
that is full of holes and try to patch them slowly.


In many cases affixing const to your code is not just a simple 'slap a 
const on here'.  It can involve careful thought and possibly redesign.


But without these changes, const is very useless, the standard library 
needs to eat its own dogfood if we want to peddle it to others.


-Steve

Vote++

--
Graham St Jack



Re: const(Object)ref is here!

2010-12-05 Thread Graham St Jack
First, I have to say that it is wonderful that someone is taking a 
serious look at this area again, and even better, you have come up with 
a compiler patch to make it happen!


Some questions (assuming your patch or something like it gets into dmd):

Does this mean that I would be able to write this:
immutable(Foo)ref foo; // create a reference
foo = new immutable(Foo)(); // re-bind it (not sure about new syntax 
for immutables)


Are there any other show-stopping syntax issues that are holding up 
widespread adoption/rollout of const-correctness?


What do Walter and Andrei think?

Does anyone know what the plan is for rolling const-correctness 
thoughout druntime and phobos (and shared/immutable in std.concurrency)? 
Having to do casting all the time is a real drag. I for one would be 
happy to help if help is needed.



On 06/12/10 11:21, Michel Fortin wrote:
After a recent discussion on this list about tail-const class 
references, it became rather clear that someone interested would have 
to implement the thing if we were to have it. So I did it. See 
enhancement request 5325 for an explanation and a patch.

http://d.puremagic.com/issues/show_bug.cgi?id=5325

Let's hope Walter likes my patch.

In the tail-const thread, I proposed the challenge of making this code 
work when an array of const object is passed as an argument:


T[] giveMeASortedArray(alias Predicate, T)(T[] t) {
// creating new array of the same length but with assignable 
elements

auto copy = new Unqual!(typeof(t[0]))[t.length];
foreach (index, value; t)
copy[index] = value;

// sorting the copy
sort!(Predicate)(copy);
return copy;
}

Well, with the patch I made it now works!... irrespective of the type 
attribute (const,immutable,shared,inout). The only modification 
required to Phobos is to make to!string() compile when passed a 
const(Object) because somehow 'sort' requires that.


Here is how the function is invoked:

void main() {
int*[] a = giveMeASortedArray!(a  b)(new int*[12]);
Object[] b = giveMeASortedArray!(a  b)(new Object[12]);

const(int*)[] c = giveMeASortedArray!(a  b)(new 
const(int*)[12]);
const(Object)[] d = giveMeASortedArray!(cast(void*)a  
cast(void*)b)(new const(Object)[12]);

}

See the strange predicate for the const(Object) version? That's 
because opCmp() in Object doesn't work with const.


Two minor modifications are required in Phobos to make the above 
compile. First, to!string(const(Object)) needs an implementation 
because somehow 'sort' requires it. Also template std.traits.isMutable 
needed an adjustment so that swap()'s template constrains are satisfied.






--
Graham St Jack



Re: Initialization of unions

2010-09-27 Thread Graham St Jack

Hi Justin,

I am using a struct as a discriminated union in my version of the 
concurrency framework, and it all seems to work just fine. Here is a 
code fragment from the code that implements a simple protocol. The code 
is generated by a template, so it is very easy to crank out a message 
struct with lots of different kinds of payload.



struct jobMsg {
string name;
this(string name) {
 this.name = name;
}
void read(InStream stream) {
 name = stream.get!string;
}
void write(OutStream stream) {
stream(name);
}
}
struct Message {
uint kind;
union {
jobMsg job;
}
this(ref jobMsg msg) {
kind = 0;
job = msg;
}
this(InStream stream) {
kind = stream.get!uint;
switch(kind) {
case 0: job.read(stream); break;
default: assert(0, Cannot read unsupported message kind);
}
}
void write(OutStream stream) {
stream(kind);
switch(kind) {
case 0: job.write(stream); break;
default: assert(0, Cannot write unsupported message kind);
}
}
}


On 23/09/10 21:58, Justin Johansson wrote:

On 23/09/2010 10:14 PM, bearophile wrote:

Justin Johansson:


One of the problems with C++ is that it is not possible
to create unions with non-primitive members (e.g. structs)
that have constructors.


Do you mean something like this?

struct S1 {
 int y;
 this(int x) { y = x; }
}

struct S2 {
 string t;
 this(string s) { t = s; }
}

union U {
 S1 s1;
 S2 s2;
}

static U u2 = { s2:S2(hello) };

void main() {
 U u = U(S1(10));
 assert(u.s1.y == 10);
 u.s2 = S2(hello);
 assert(u.s2.t == hello);
 // U u3 = U(S2(hello)); // not possible
}


Yes, but not yes; something like that.  You are obviously
one step ahead of me so perhaps I should give up or else
post the exact problem in C++.  Still, it looks likes
from what you have shown that D has some better union
construction syntax than C++.

I hope others can throw in their 2 cents.

Bye,
Justin




--
Graham St Jack



Re: d.vim 0.20

2010-08-31 Thread Graham St Jack

On 31/08/10 03:38, Jesse Phillips wrote:

There is a new version of the D syntax file for Vim. This is version 0.20 and 
is available at

http://www.vim.org/scripts/script.php?script_id=379

* Added missing keywords for D 2.0 compiler 2.047
* Added special highlighting of known versions/scopes/annotations
(thanks to Shougo Matsushita)

* Added highlighting of ASM Op Codes in asm blocks.

I highly suggest you drop this latest version into your syntax folder 
~/.vim/syntax Linux and ~/_vimfiles/syntax Windows (where ~ is users directory, 
not documents).

I am the new maintainer of this file so please direct any comments, 
suggestions, patches my way at jesse.k.phillip...@gmail.com
   

thanks++

--
Graham St Jack



Re: The Status of Const

2010-08-15 Thread Graham St Jack

On 14/08/10 14:39, Denis Koroskin wrote:

Graham St Jack Wrote:


For me, the key problem is that a class object reference has the same
const/immutable/shared attribute as the object on the heap that it
refers to. This is sometimes what you need, but more often you want a
non-shared, mutable reference to a const/immutable/shared object.

You can achieve this with pointers for arrays, structs and primitive
types, but not with classes because a class pointer is just a pointer to
a reference.



I discussed a possibility of requiring '*' to denote both references AND 
pointers before TDPL was out. It would solve a whole bunch of language issues, 
including this one:

Rebindable!(immutable(Foo)) bar; -  immutable(Foo)* bar;

There is a lot more benefits in the proposal than you might think at first. 
Here is the link: 
http://www.digitalmars.com/d/archives/digitalmars/D/What_if_D_would_require_for_reference_types_104816.html



--
Graham St Jack




Thanks for that.

I must admit that the proposal looks really good to me, especially if it 
is compulsory to always use a pointer - i.e. cannot have a class object 
by value. But - for some reason I don't understand, this and the many 
other proposals I have seen don't get up.


Maybe what is needed here is for someone (Walter?) to write up the 
results of the various const/immutable/shared discussions, and put it on 
the website, together with suggested usage idioms. Then we will all 
understand why things are the way they are, and how we should be using 
these language features. This issue has been a running sore for a long 
time, but maybe all it needs is an authoritative write-up to sort it out.



--
Graham St Jack


Re: The Status of Const

2010-08-13 Thread Graham St Jack

On 14/08/10 05:55, Walter Bright wrote:

Graham St Jack wrote:

For me, the key problem is that a class object reference has the same
const/immutable/shared attribute as the object on the heap that it
refers to. This is sometimes what you need, but more often you want a
non-shared, mutable reference to a const/immutable/shared object.


I struggled with this for a long while before I eventually came to the
conclusion that I was thinking about class objects as a reference and
the instance, and that those two were separable concepts. They are not.
A reference type is implicitly treated like a value type as far as
accessing its members go. Trying to separate out the two is a
fundamental misunderstanding of what reference types are all about.
Semantically, they are much more than just a pointer to the instance.



You can achieve this with pointers for arrays, structs and primitive
types, but not with classes because a class pointer is just a pointer
to a reference.


The way to do it with class is take a pointer to the class:

class C { ... }

const(C)*[]; // array of pointers to const classes

just like you'd do with a struct.


I get it - I think. I will give this a try and see how it works in practice.

--
Graham St Jack


Re: The Status of Const

2010-08-12 Thread Graham St Jack
I have tried using const/immutable/shared several times, and am 
currently in the process of giving it another shot, with much more 
success that before, but it is hard work.


The major language hassle for me is that a class reference has the same 
const/immutable/shared type as the object is refers to, unlike pointers. 
I know that Rebindable is a workaround, but I don't find it satisfactory 
- essentially it uses brute-force casting to defeat the type system, and 
isn't syntactically identical to the bound type.


The data I pass between threads has to pass the !hasAliasing test, and I 
haven't found a practical way to make it work for classes. What works 
best for me is a struct with a pointer to immutable data like so:


struct Foo {
struct Payload {
...
   }
   immutable(Payload)* payload;
   ...
}

Foo can then be passed, contained by value and assigned to, just like 
any other value type. Containing an immutable instance of Foo is ok too, 
if you need another layer of !hasAliasing. I tend to define all my 
non-trivial building-block data types this way, and pass them by value.


With careful design of my multi-threaded code, I can define a set of 
messages to pass between threads that don't need to contain complex data 
structures. The resultant design is always an improvement over the more 
complex interface that first comes to mind, so I find that the type 
system is pushing me in a good direction.


The next big hurdle (as you pointed out) is that druntime and phobos 
aren't designed for const/immutable/shared. For example, InternetAddress 
fails the !hasAliasing test, and concurrency Mailboxes defeat the type 
system rather than being shared themselves, and don't insisting that 
message parameters have to be !hasAliasing. So far I have had to 
implement my own concurrency, socket and condition modules to overcome 
these issues, and I'm sure those are just the beginning.


So there are plenty of bumps in the road, but it does look like it is 
finally possible to use const/immutable/shared if you are determined 
enough. That said, it needs to be way, way easier before wide adoption.


The library issues can be addressed easily enough - It didn't take me 
long to pull off versions that worked ok (Linux only I'm afraid). 
However, the issue with classes doesn't look so easy, and that seriously 
limits what can be passed in messages.


Is there any plan to introduce some way of having a mutable reference to 
an immutable class object on the heap? Do others see this as a problem 
at all?


On 13/08/10 08:26, dsimcha wrote:

This is from a discussion that originated on the Phobos mailing list, but I
thought I'd bring up the question of what should be done about const on the
newsgroup to see what others think:

Despite its theoretical beauty, I find D's const/immutable system to be
utterly useless for all but the simplest use cases.  I made a serious attempt
a while back to use it in a real multithreaded program.  In hindsight it was
more trouble than it was worth, largely for three reasons:

1.   It's difficult to create non-trivial immutable data structures, and often
impossible without relying on either unchecked casts or unnecessary copying.

2.  Much generic code in Phobos (even things as simple as std.math.pow()
before I recently fixed it) behaves incorrectly when given const/immutable
data.  This also applies to other libraries I use, including ones that I'm the
main author of, so I'm just as guilty of it as anyone.  Given that noone,
including me, seems to be able to get const to interact well with generic
code, perhaps we need a language-level solution.

3.  inout is currently so bug-ridden it's not even funny.  (Though this is
clearly fixable long-term, once we get higher priority stuff off our plates.)

It would have probably been better if this was brought to a head sooner, but
it's better late than never.  Do others agree that D's const system is
difficult to impossible to use properly?  Has anyone successfully used D's
const system in a non-trivial setting despite these limitations?  If so, was
it more trouble than it was worth in hindsight?  How can these limitations be
worked around and/or fixed?
   



--
Graham St Jack



Re: The Status of Const

2010-08-12 Thread Graham St Jack

On 13/08/10 09:51, Brad Roberts wrote:

On Thu, 12 Aug 2010, dsimcha wrote:

   

This is from a discussion that originated on the Phobos mailing list, but I
thought I'd bring up the question of what should be done about const on the
newsgroup to see what others think:

Despite its theoretical beauty, I find D's const/immutable system to be
utterly useless for all but the simplest use cases.  I made a serious attempt
a while back to use it in a real multithreaded program.  In hindsight it was
more trouble than it was worth, largely for three reasons:

1.   It's difficult to create non-trivial immutable data structures, and often
impossible without relying on either unchecked casts or unnecessary copying.

2.  Much generic code in Phobos (even things as simple as std.math.pow()
before I recently fixed it) behaves incorrectly when given const/immutable
data.  This also applies to other libraries I use, including ones that I'm the
main author of, so I'm just as guilty of it as anyone.  Given that noone,
including me, seems to be able to get const to interact well with generic
code, perhaps we need a language-level solution.

3.  inout is currently so bug-ridden it's not even funny.  (Though this is
clearly fixable long-term, once we get higher priority stuff off our plates.)

It would have probably been better if this was brought to a head sooner, but
it's better late than never.  Do others agree that D's const system is
difficult to impossible to use properly?  Has anyone successfully used D's
const system in a non-trivial setting despite these limitations?  If so, was
it more trouble than it was worth in hindsight?  How can these limitations be
worked around and/or fixed?
 

For discussions like this, I think it's essential to distinguish between
the language vs the runtime + core libraries.  I recognize what matters is
the end result usability, but examining the layers independently is really
important.

So, which are you talking about (could well be both)?
   
For me, the key problem is that a class object reference has the same 
const/immutable/shared attribute as the object on the heap that it 
refers to. This is sometimes what you need, but more often you want a 
non-shared, mutable reference to a const/immutable/shared object.


You can achieve this with pointers for arrays, structs and primitive 
types, but not with classes because a class pointer is just a pointer to 
a reference.



--
Graham St Jack



Re: The Status of Const

2010-08-12 Thread Graham St Jack

On 13/08/10 10:08, Andrei Alexandrescu wrote:

Trass3r wrote:
Well isn't it natural that a constness system has a much larger 
impact than just some syntax additions.
I don't see any flaws in its design. The implementation is of course 
still buggy though and needs to mature.


I agree. There are very severe bugs and undue limitations in today's 
const. Having a comprehensive discussion of const's status and role in 
current and future D idioms is a great idea. We should start it with a 
scrutiny of the reported and possibly unreported bugs in the feature.



Andrei

I also agree that cost is worth the effort.

Most of the roadblocks are relatively easy to overcome by rolling 
const-correctness through druntime and phobos.


However, I still regard the language design decision of a class 
reference having the same constness as the object it refers to as a 
major language design problem. I would be delighted if someone could 
point out to me how to neatly work around this though.


--
Graham St Jack



Re: The Status of Const

2010-08-12 Thread Graham St Jack

On 13/08/10 10:18, Jonathan M Davis wrote:

On Thursday, August 12, 2010 17:38:28 Graham St Jack wrote:
   

For me, the key problem is that a class object reference has the same
const/immutable/shared attribute as the object on the heap that it
refers to. This is sometimes what you need, but more often you want a
non-shared, mutable reference to a const/immutable/shared object.

You can achieve this with pointers for arrays, structs and primitive
types, but not with classes because a class pointer is just a pointer to
a reference.
 

Hence the hack that is Rebindable!().

Oh, and you _can_ achieve pointers to classes, but what you normally use are
references, which do have the problem of not being able to be split between the
reference and referent types.

- Jonathan M Davis
   
So how do you get a pointer to an object? Taking the address of an 
object reference gives you a pointer to the reference, not the object, 
which is fair enough. As far as I know there isn't a way to get a 
pointer to the object itself, and even if you could, how do you use such 
a thing?



--

Graham St Jack



Re: A working backtrace for linux

2010-08-03 Thread Graham St Jack

On 04/08/10 05:30, Sean Kelly wrote:

Trass3r Wrote:

   

Which reminds me that there are still no traces for Windoze, even though
Tango has been providing for quite some time IIRC.
 

Then perhaps the person who wrote the Tango Win32 backtrace will submit it to 
Phobos :-)  I've been busy with other things recently, but Win32 backtrace is 
coming.  It's just more work than the 30 minutes it took me to do the Linux/OSX 
one (which admittedly needs some work as well).
   
Sean, is there any chance of you rolling some of the good stuff in this 
code into druntime?


In particular, it would be very nice to get symbol names in a stacktrace 
rather than a bunch of addresses, and even nicer to get a stacktrace on 
a SIGSEGV.


--
Graham St Jack



Re: A working backtrace for linux

2010-08-03 Thread Graham St Jack

On 04/08/10 12:47, Brad Roberts wrote:

On 8/3/2010 8:09 PM, Sean Kelly wrote:
   

Graham St Jack Wrote:
 

Sean, is there any chance of you rolling some of the good stuff in this
code into druntime?

In particular, it would be very nice to get symbol names in a stacktrace
rather than a bunch of addresses, and even nicer to get a stacktrace on
a SIGSEGV.
   

You can get the symbol names by adding -L--export-dynamic to your DFLAGS in 
dmd.conf.  That option is on by default on OSX and I didn't realize it was 
different on Linux.  I'll sort out demangling as well, it's just a bit more 
work.  I like the stack trace code provided, but it uses a lot of modules that 
aren't available to druntime so it would be difficult to use directly.
 

see also my notes in bug 1001, the one all about this topic.
   
Thanks for the heads-up - I will keep a closer eye on the bug-list in 
future. Its great to see all the action going on under the hood.


--
Graham St Jack



Re: poll about delete

2010-07-27 Thread Graham St Jack

On 28/07/10 05:47, Andrei Alexandrescu wrote:

Max Samukha wrote:

On 07/27/2010 10:53 PM, Andrei Alexandrescu wrote:

and scope storage class.


If scope storage class is going, we need a library equivalent. Current
'scoped' is not good due to 4500.


Agreed. I know how to fix it.

Andrei


I missed the previous discussions about removing the scoped storage 
class. Would you mind re-stating the argument here, or post a link to it?


FWIW I'm happy for delete to be removed.

--
Graham St Jack


Re: poll about delete

2010-07-27 Thread Graham St Jack

On 28/07/10 07:50, Andrei Alexandrescu wrote:

Graham St Jack wrote:

On 28/07/10 05:47, Andrei Alexandrescu wrote:

Max Samukha wrote:

On 07/27/2010 10:53 PM, Andrei Alexandrescu wrote:

and scope storage class.


If scope storage class is going, we need a library equivalent. Current
'scoped' is not good due to 4500.


Agreed. I know how to fix it.

Andrei


I missed the previous discussions about removing the scoped storage
class. Would you mind re-stating the argument here, or post a link to it?

FWIW I'm happy for delete to be removed.


In brief scope is unsafe and impossible to make safe without extensive
changes to the language.

Andrei


Thanks. I definitely agree that it should go if it can't be made to work 
properly.


--
Graham St Jack


Concurrency

2010-07-25 Thread Graham St Jack
I have been using std.concurrency for a while, and have been very 
impressed by it. In particular, it was easy to get a complex 
multi-threaded application going with std.concurrency. The 
thread-local-storage behaviour of D is really cool too.


However, I have had some problems with std.concurrency (most of which 
I'm sure are already being addressed by Sean). In particular, I wanted a 
way to select on multiple file-descriptors so that I could (say) send 
commands to a thread that also reads from a blocking file-descriptor 
like a serial port, UDP socket or GTK main loop. I also wanted to 
experiment with the amazing template capabilities of D that I found out 
about in the book, and see if I could generate boiler-plate 
message-passing code that doesn't rely on magic like Variant.


The attached file is where I am at so far. It works, but still needs a 
lot of work to bring it up to scratch. The reason for posting it here is 
to stimulate some discussion about how D's standard concurrency module 
should behave (and maybe get a few helpful tips).


Please take a look and let me know what you think.

--
Graham St Jack
module alt.concurrency;

//public import alt.io;

import std.algorithm;
import std.contracts;
import std.stdio;
import std.conv;
import std.traits;
import std.typecons;
import std.typetuple;

import core.sync.condition;
import core.sync.mutex;
import core.thread;
import core.stdc.stdlib;


//
// Provides an alternative message-passing concurrency implementation
// to std.concurrency. It is similar to std.concurrency, but is different in that:
// * Messages cannot contain references to mutable data.
// * Message queues (Channels) are explicitly created and passed to threads as
//   arguments to spawn().
// * Channels are synchronized (and thus shared).
// * The types of messages a Channel supports are well-defined.
// * Messages are processed in order.
// * Multiple threads can receive from the same Channel.
// * Out of band messages are not supported directly, but can be implemented via
//   additional Channels.
// * Channels have an internal pipe that can be used in a Selector to allow
//   a thread to receive input from multiple Channels and file-descriptor devices
//   such as sockets and pipes.
// * There is no automatic thread-termination behaviour.
//
// The motivation for this module is to stimulate some discussion about
// how D's standard message-passing support should behave.
// It is also a learning experience for the author.
// The std.concurrency issues of most interest to the author are:
// * Messages are not named - they are inferred from the types.
// * Lack of compile-time checking.
// * It allows mutable references to be sent in messages.
//
// Graham St Jack, July 2010.
// This is free software - do with it as you will.
//
// Currently only Linux is supported.
//
// TODO - prevent non-shareable data from being passed to spawn().
// TODO - handling of signals.
// TODO - print demangled stack trace on unexpected thread death.
// TODO - provide Windows and Mac support in alt.io, tidy up alt.io
//and debug it properly.
//


//
// A Channel for sending messages between threads.
// The internal pipe is used to block removal until a message is available,
// and to provide a file-descriptor to select on. Multiple threads
// may add and remove messages from the queue, but usually one thread
// adds and one other thread removes.
//

public class ChannelFull : Exception {
this() { super(channel full); }
}

public class ChannelFinalized: Exception {
this() { super(channel finalized); }
}

// A SelectableReader returned from a Channel for use in a Selector
// The Channel itself cannot be used because it is shared.
/*
class Selectable : ISelectableReader {
private int mFd;

this(int fd) {
mFd = fd;
}

// ISelectableReader implementation:
override uint read(void * buffer, uint count) {
assert(false, read is not supported);
}
override int read_descriptor() {
return mFd;
}
}
*/

// FIXME - class should be synchronized, but druntime.core.sync's
// Condition class doesn't work with synchronized classes or methods yet.
class Channel(T) {
private {
struct Node {
T payload;
Node* next;

this(T payload) {
this.payload = payload;
}
}

Node* mFront;
Node* mBack;
uint  mCapacity;
uint  mCount;
//ubyte mZero;
//Pipe  mPipe;
bool  mFinalized;
Mutex mMutex;
Condition mReadCondition;
Condition mWriteCondition;
}

this(uint capacity = 0) {
mCapacity   = capacity;
//mPipe   = new Pipe();
mMutex  = new Mutex();
mReadCondition  = new Condition(mMutex);
mWriteCondition = new Condition(mMutex);
}

// Return a new Selectable that can be used in a Selector

Re: Concurrency

2010-07-25 Thread Graham St Jack

On 26/07/10 13:48, Sean Kelly wrote:

Graham St Jack Wrote:

   

However, I have had some problems with std.concurrency (most of which
I'm sure are already being addressed by Sean). In particular, I wanted a
way to select on multiple file-descriptors so that I could (say) send
commands to a thread that also reads from a blocking file-descriptor
like a serial port, UDP socket or GTK main loop.
 

Hm... this is essentially what libev and libevent do.  The trick is mostly 
making this work in a consistent and performant manner on both Posix and 
Windows.  On Posix, the read event simply tells you data is available, while on 
Windows the read event hands the data to you directly.  The former works quite 
well with messaging while the latter... well, it's kind of weird.
   
I don't know much about Windows programming, but I was expecting this to 
be the sticking point. So do we have a solution in D for this? For me, 
it is the key issue with std.concurrency as it stands.


Using the Pipe approach as I did in Channel, maybe a Windows version 
could allow a byte to be removed from the Pipe for each message, and 
another byte immediately put on to replace it if the Channel was not 
then empty.

I like that you're playing with Channels, by the way.  I chose the messaging 
API in std.concurrency because it can have a range of more structured models 
built on top of it, so I think it's more likely to see broad use done this way. 
 Maybe channels will be the first :-)
   
The Channels I proposed were really just a first try at doing code 
generation, but they do work really well. I particularly like being able 
to print out the generated code to see what you are getting. I must 
admit that I find Variant perplexing, and had issues with the message 
size limitation and no prohibition on aliased message parameters.


In working with both std.concurrency and alt.concurrency, I have found 
that alt.concurrency has some advantages such as:


Creating Channels first and providing them as arguments to spawn() is 
simpler than spawning threads and passing Tids in messages.


Being able to use the same set of parameter types in two different 
messages, and having names for the messages is clearer.


Being able to have multiple threads reading messages from the same 
Channel - something I need (well, want because it is much easier than 
double-handling all the messages through an intermediary) on my current 
project.


The benefit of compile-time checking.


Of course std.concurrency has lots of bonuses too. What I am after is a 
discussion that leads to a std.concurrency that is better still.



By the way, how are you getting on with rolling out shared through 
core.sync? I'm very keen to find out if shared can at last be used as 
intended - such as for implementing a Channel. I could lend a hand if 
you need one.


--
Graham St Jack



Re: TDPL, shared data, and Phobos

2010-07-22 Thread Graham St Jack

On 23/07/10 10:23, Sean Kelly wrote:

awishformore Wrote:

   

On 22/07/2010 01:49, Robert Jacques wrote:
 

Have you tried core.sync.rwmutex? Also, please remember that CREW locks
are not composable and can easily lead to dead-locks.
   

Afaik, the current rwmutex is a wrapper around two separate mutexes (one
for readers, one for writers) and you have to decide whether readers or
writers get precedence, meaning that ether all writers in the queue have
to wait if just one reader has to write or all writers in the queue have
to wait if there is a single reader comes up.

This is very unlike the behaviour I would like to see; I would expect
readers and writers to be in the same queue, meaning the only difference
between the rw and the normal mutex would be that all subsequent readers
in the queue can read at the same time.
 

ReadWriteMutex exposes a read and write interface, but there certainly aren't 
two actual mutexes underneath.  It's true that the implementation doesn't 
explicitly maintain a queue, but this is intentional.  If readers and writers 
in the queue have different thread priorities set, those priorities should be 
honored, and it's pointless to write all that code in druntime when the OS 
takes care of it for us.  Instead, those waiting for access to the mutex all 
block on a condition variable and whoever wakes up first wins.  It's up the OS 
to make sure that thread priorities are honored and starvation doesn't occur.
   
It isn't clear that thread priorities will do the job here. I have been 
burned before by things like priority inheritance chaining, and other 
ways that thread priorities can be elevated for potentially long periods 
of time.


Priority inheritance chaining goes like this:

Thread low locks mutex A, then mutex B

Thread high tries to lock mutex B, elevating low's priority to high's so 
that high can get the mutex quickly.


When thread low releases mutex B (letting high get it), the OS has 
trouble figuring out what low's priority should now be, and leaves it 
elevated until it releases all mutexes it still has (mutex A in this case).


Low is now running at a high priority, preventing thread medium from 
getting any CPU.



This scenario happened for me with vxWorks some time back, and is the 
reason I no longer do much work at all while I have a mutex locked. I am 
confident that it is a real problem to this day.


--
Graham St Jack



Re: TDPL, shared data, and Phobos

2010-07-19 Thread Graham St Jack
On Sun, 18 Jul 2010 16:05:08 +, Sean Kelly wrote:

 Graham St Jack graham.stj...@internode.on.net wrote:
 On Sat, 17 Jul 2010 11:42:03 -0400, Sean Kelly wrote:
 
 The casts are necessary because I haven't yet applied 'shared' to
 druntime.  I ran into a few issues when doing so and rolled back my
 changes.  I'll give it another shot before the next release.
 
 I'm glad you announced you intention - I was just about to roll up my
 sleeves and give it a go for Condition, but will wait for the next
 release.
 
 Like all my previous attempts to use shared, I have waited for quite a
 
 while for things to improve, tried using shared again, hit a brick wall
 and resorted to defeating the compiler's detection of shared data.
 
 TDPL raised my hopes without actually making it clear how to use
 synchronized classes. Alas, it seems to me that they still aren't
 usable
 in practice. With any luck the problems are just library issues which
 can
 be fixed relatively easily.
 
 Like Brian Palmer, I am frustrated by the lack of documentation about
 shared and druntime's sync package, and am happy to lend a hand if that
 would be helpful.
 
 The code I am trying to write is a simple synchronized class with a
 Condition, but I can't create a Condition on a shared this.
 
 A cut-down version of what I want to write is:
 
 synchronized class Foo {
   Condition mCondition;
   this() {
 mCondition = cast(shared) new Condition(this);
   }
   void some_method() {
   }
 }
 
 I realise that Condition wants a Mutex, but a synchronized class
 already
 has an implicit one which is implicitly used by all the methods, so the
 above is definitely what I want to write.
 
 What I have to write instead (which avoids the compiler noticing that
 anything is being shared) is:
 
 class Foo {
   Mutex mMutex;
   Condition mCondition;
   this() {
 mMutex = new Mutex();
 mCondition = new Condition(mMutex);
   }
   void some_method() {
 synchronized(mMutex) {
 }
   }
 }
 
 The latter works just fine, but it is very disappointing after all the
 
 fuss about how important shared is that you can't actually use it for
 the
 most mainstream of all uses - a synchronized class with a condition
 (which is what a message queue between threads is supposed to be).
 
 new Mutex(this) makes the mutex the object monitor, so it will be what's
 locked for synchronized functions.

That's cool. I look forward to shared not being an issue ;-)

I assume that when Condition and Mutex are shareable, I will then (from 
your other post) write:

synchronized class Foo {
  Mutex mMutex;
  Condition mCondition;
  this() {
mMutex = cast(shared) new Mutex(this);
mCondition = cast(shared) new Condition(mMutex);
  }
  void some_method() {
...
mCondition.notify; // ok because mMutex is locked
  }
}


Re: Debugging

2010-07-17 Thread Graham St Jack
On Fri, 16 Jul 2010 21:47:50 +, Sean Kelly wrote:

 -profile currently doesn't work with multithreaded apps.

Darn. Are there plans to sort that out?


Re: TDPL, shared data, and Phobos

2010-07-17 Thread Graham St Jack
On Sat, 17 Jul 2010 11:42:03 -0400, Sean Kelly wrote:

 The casts are necessary because I haven't yet applied 'shared' to
 druntime.  I ran into a few issues when doing so and rolled back my
 changes.  I'll give it another shot before the next release.

I'm glad you announced you intention - I was just about to roll up my 
sleeves and give it a go for Condition, but will wait for the next 
release.

Like all my previous attempts to use shared, I have waited for quite a 
while for things to improve, tried using shared again, hit a brick wall 
and resorted to defeating the compiler's detection of shared data.

TDPL raised my hopes without actually making it clear how to use 
synchronized classes. Alas, it seems to me that they still aren't usable 
in practice. With any luck the problems are just library issues which can 
be fixed relatively easily.

Like Brian Palmer, I am frustrated by the lack of documentation about 
shared and druntime's sync package, and am happy to lend a hand if that 
would be helpful.

The code I am trying to write is a simple synchronized class with a 
Condition, but I can't create a Condition on a shared this.

A cut-down version of what I want to write is:

synchronized class Foo {
  Condition mCondition;
  this() {
mCondition = cast(shared) new Condition(this);
  }
  void some_method() {
  }
}

I realise that Condition wants a Mutex, but a synchronized class already 
has an implicit one which is implicitly used by all the methods, so the 
above is definitely what I want to write.

What I have to write instead (which avoids the compiler noticing that 
anything is being shared) is:

class Foo {
  Mutex mMutex;
  Condition mCondition;
  this() {
mMutex = new Mutex();
mCondition = new Condition(mMutex);
  }
  void some_method() {
synchronized(mMutex) {
}
  }
}

The latter works just fine, but it is very disappointing after all the 
fuss about how important shared is that you can't actually use it for the 
most mainstream of all uses - a synchronized class with a condition 
(which is what a message queue between threads is supposed to be).


Re: Debugging

2010-07-17 Thread Graham St Jack
On Sat, 17 Jul 2010 14:43:38 -0400, Sean Kelly wrote:

 Graham St Jack Wrote:
 
 On Fri, 16 Jul 2010 21:47:50 +, Sean Kelly wrote:
 
  -profile currently doesn't work with multithreaded apps.
 
 Darn. Are there plans to sort that out?
 
 It's been on my to do list for ages.  Timing data is less/differently
 useful for multithreaded code, but it should at least not crash, unlike
 now.

I find profiling very useful in multi-threaded programs for assisting 
with optimisation, and am keen for it to be possible.

I use C++ in my day job (with gcc), and recently went through a lot of 
pain trying to get gprof to work, only to discover that it fundamentally 
doesn't work on multi-threaded code. I guess that is fair enough given 
that instrumented code can't use something as simple as a high-resolution 
clock to measure how long things take.

What I ended up using was sysprof, which is an external program that does 
statistical sampling of the whole system. It works really well, and 
produces a respectable call graph that shows very clearly where the time 
is being spent. However, when I try it with a D2 program, I don't get a 
call graph - presumably because it doesn't understand the stack frames 
and so can't work out the call graph. This renders it almost useless for 
D programs.


Debugging

2010-07-13 Thread Graham St Jack
I have jumped back onto the D2 band-wagon after a long absence, read 
Andrei's book, and am having a great time cutting heaps of D code. My 
increase in productivity and happiness when compared to working in C++ is 
enormous. 

Bug thumbs up to everyone involved with D2, Phobos and the book.

One area I am having a bit of trouble with is debugging. Can anyone help 
me out with how to debug a D2 program in Linux? Currently I am reduced to 
printing out heaps of debug text.

Specifically:

Stack Trace:


I can't get the D2 stack-trace to work properly. All I get is something 
like this, which isn't helpful:

Segmentation fault

The code I used to generate this was:
import std.stdio;
import std.file;
void foo(File file) {
file.flush;
}
void main(string[] args) {
File file;
foo(file);
}
Is stack-trace support broken, or do I have to do something to enable it?

GDB:


What is the status of D support in GDB? The last post I saw was back in 
April. It is currently hard work to debug with gdb when it doesn't 
understand D name mangling.

Profiling:
--

How do I profile a D2 program? When I try -profile in dmd, the resultant 
executable crashes with a segfault when I try to run it. When I try 
sysprof, I get a handful of mangled names, and no call graph.


Re: Debugging

2010-07-13 Thread Graham St Jack
On Tue, 13 Jul 2010 03:55:08 -0400, bearophile wrote:

 Graham St Jack:
 How do I profile a D2 program? When I try -profile in dmd, the
 resultant executable crashes with a segfault when I try to run it.
 
 Are you able to produce a small test case of this bug?
 
 Bye,
 bearophile

Small test cases don't crash. I will spend a bit of time experimenting 
with my way-too-big test case to find out why it crashes when run after 
being compiled with -profile, and post my results here.

One thing I noticed was that the trace.log file doesn't demangle the 
names properly either.


Re: Debugging

2010-07-13 Thread Graham St Jack
On Tue, 13 Jul 2010 08:48:50 -0400, Steven Schveighoffer wrote:

 On Tue, 13 Jul 2010 02:26:22 -0400, Graham St Jack
 graham.stj...@internode.on.net wrote:
 
 I have jumped back onto the D2 band-wagon after a long absence, read
 Andrei's book, and am having a great time cutting heaps of D code. My
 increase in productivity and happiness when compared to working in C++
 is enormous.

 Bug thumbs up to everyone involved with D2, Phobos and the book.

 One area I am having a bit of trouble with is debugging. Can anyone
 help me out with how to debug a D2 program in Linux? Currently I am
 reduced to printing out heaps of debug text.

 Specifically:

 Stack Trace:
 

 I can't get the D2 stack-trace to work properly. All I get is something
 like this, which isn't helpful:

 Segmentation fault

 The code I used to generate this was: import std.stdio;
 import std.file;
 void foo(File file) {
 file.flush;
 }
 void main(string[] args) {
 File file;
 foo(file);
 }
 Is stack-trace support broken, or do I have to do something to enable
 it?
 
 Seg faults do not generate stack traces in Linux/MacOS.  This is because
 a segmentation fault is generated by a signal, and it's unsafe to throw
 exceptions from signals.
 
 I believe seg faults can generate exceptions in Windows, but I'm not
 sure.
 
 Your best bet is to get a debugger working, and it will halt on the
 signal.  As I understand it, a lot of good work was done recently on dmd
 (can't remember who did it) to get it working better with gdb.
 
 -Steve

Thanks. I will persist with gdb and look forward to the D support coming 
through.


Re: Debugging

2010-07-13 Thread Graham St Jack
On Tue, 13 Jul 2010 10:34:41 -0500, Andrei Alexandrescu wrote:

 On 07/13/2010 01:26 AM, Graham St Jack wrote:
 I have jumped back onto the D2 band-wagon after a long absence, read
 Andrei's book, and am having a great time cutting heaps of D code. My
 increase in productivity and happiness when compared to working in C++
 is enormous.

 Bug thumbs up to everyone involved with D2, Phobos and the book.
 [snip]
 
 Thanks. Bug thumbs up? Clearly you had debugging on your mind :o).
 
 Check http://www.zerobugs.org/.
 
 
 Andrei

Freudian slip...

I love the book by the way - I couldn't put it down. D is totally awesome 
now, and there were heaps of cool new features that I didn't know about.

Thanks again.


Re: Debugging

2010-07-13 Thread Graham St Jack
On Tue, 13 Jul 2010 15:29:35 -0400, Jesse Phillips wrote:

 Graham St Jack Wrote:
 
 Specifically:
 
 Stack Trace:
 
 
 I can't get the D2 stack-trace to work properly. All I get is something
 like this, which isn't helpful:
 
 Segmentation fault
 
 The code I used to generate this was: import std.stdio;
 import std.file;
 void foo(File file) {
 file.flush;
 }
 void main(string[] args) {
 File file;
 foo(file);
 }
 Is stack-trace support broken, or do I have to do something to enable
 it?
 
 While you aren't asking why, 'file' is initialized to null and is not a
 stack allocated class as it would be in C++.

Yes - it was a contrived example designed to deliberately segfault.

 
 The first step to debugging is to use the -gc flag instead of -g. The
 unreleased version of GDB has the patch for D mangling, otherwise you
 need the symbols to mimic C. Then you can run your program with GDB.

Thanks - I have been doing that, but like I said, it is hard work 
mentally demangling the names.

 
 As you should be familiar with. You can get the stack trace form GDB if
 you enable core dumps: $ ulimit -c 5000  dmd -gc test.d  ./test 
 gdb ./test core

I didn't know about that, thanks. It looks like a more convenient way of 
debugging segfaults than running the program in gdb directly. I will give 
it a go.


Re: Debugging

2010-07-13 Thread Graham St Jack
On Tue, 13 Jul 2010 21:38:09 +, Graham St Jack wrote:

 On Tue, 13 Jul 2010 03:55:08 -0400, bearophile wrote:
 
 Graham St Jack:
 How do I profile a D2 program? When I try -profile in dmd, the
 resultant executable crashes with a segfault when I try to run it.
 
 Are you able to produce a small test case of this bug?
 
 Bye,
 bearophile
 
 Small test cases don't crash. I will spend a bit of time experimenting
 with my way-too-big test case to find out why it crashes when run after
 being compiled with -profile, and post my results here.
 
 One thing I noticed was that the trace.log file doesn't demangle the
 names properly either.

Here is a gdb stacktrace from a program that was compiled with -profile 
and -gc. The program is too big to post here, but it works just fine 
without the -profile. Note that the problem seems to be something to do 
with variant and/or concurrency. I don't like my chances, but I will dig 
deeper.

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xf7521b70 (LWP 32218)]
0x080834cc in trace_epi ()
(gdb) bt
#0  0x080834cc in trace_epi ()
#1  0x0806ee56 in _trace_epi_n ()
#2  0xf7520ee4 in ?? ()
#3  0x08057b4d in 
_D3std7variant17__T8VariantNVk24Z8VariantN59__T7handlerTS3std8typecons24__T5TupleTC3bob7NewFileZ5TupleZ7handlerFE3std7variant17__T8VariantNVk24Z8VariantN4OpIDPG24hPvZi
 
(parm=0xf7520eac, pStore=0x0, 
selector=3) at /home/grahams/local/dmd2/linux/bin/../../src/phobos/
std/variant.d:248
#4  0x08061310 in 
_D3std7variant17__T8VariantNVk24Z8VariantN62__T10convertsToTS3std8typecons23__T5TupleTC3bob6ActionZ5TupleZ10convertsToMFZb
 
(this=0xf7520ec8)
at /home/grahams/local/dmd2/linux/bin/../../src/phobos/std/
variant.d:584
#5  0x080607ec in 
_D3std11concurrency10MessageBox130__T3getTDFS3std11concurrency3TidZvTDFC3bob6ActionZvTDFC3bob7NewFileZvTDFAyaZvTDFC3bob11UpdatedFileZvTDFC3bob11ScannedFileZvTDFbZvZ3getMFDFS3std11concurrency3TidZvDFC3bob6ActionZvDFC3bob7NewFileZvDFAyaZvDFC3bob11UpdatedFileZvDFC3bob11ScannedFileZvDFbZvZv9onUserMsgMFS3std11concurrency7MessageZb
 
(this=0xf7521038, msg=...)
at /home/grahams/local/dmd2/linux/bin/../../src/phobos/std/
concurrency.d:360
#6  0x08061213 in 
_D3std11concurrency10MessageBox130__T3getTDFS3std11concurrency3TidZvTDFC3bob6ActionZvTDFC3bob7NewFileZvTDFAyaZvTDFC3bob11UpdatedFileZvTDFC3bob11ScannedFileZvTDFbZvZ3getMFDFS3std11concurrency3TidZvDFC3bob6ActionZvDFC3bob7NewFileZvDFAyaZvDFC3bob11UpdatedFileZvDFC3bob11ScannedFileZvDFbZvZv4scanMFKS3std11concurrency36__T4ListTS3std11concurrency7MessageZ4ListZb
 
(this=0xf7521038, list=0xf7d26dc8)
at /home/grahams/local/dmd2/linux/bin/../../src/phobos/std/
concurrency.d:449
#7  0x08060555 in 
_D3std11concurrency10MessageBox130__T3getTDFS3std11concurrency3TidZvTDFC3bob6ActionZvTDFC3bob7NewFileZvTDFAyaZvTDFC3bob11UpdatedFileZvTDFC3bob11ScannedFileZvTDFbZvZ3getMFDFS3std11concurrency3TidZvDFC3bob6ActionZvDFC3bob7NewFileZvDFAyaZvDFC3bob11UpdatedFileZvDFC3bob11ScannedFileZvDFbZvZv
 
(this=0xf7d26dc0, _param_6=57795602383664, 
_param_5=577955439440031408, _param_4=577954855324479152, 
_param_3=577954408647880368, _param_2=577953807352458928, 
_param_1=577952742200569520, _param_0=577952226804494000) at /home/
grahams/local/dmd2/linux/bin/../../src/phobos/std/concurrency.d:463
#8  0x080603f0 in 
_D3std11concurrency134__T7receiveTDFS3std11concurrency3TidZvTDFC3bob6ActionZvTDFC3bob7NewFileZvTDFAyaZvTDFC3bob11UpdatedFileZvTDFC3bob11ScannedFileZvTDFbZvZ7receiveFDFS3std11concurrency3TidZvDFC3bob6ActionZvDFC3bob7NewFileZvDFAyaZvDFC3bob11UpdatedFileZvDFC3bob11ScannedFileZvDFbZvZv
 
(_param_6=57795602383664, _param_5=577955439440031408, 
_param_4=577954855324479152, _param_3=577954408647880368, 
_param_2=577953807352458928, _param_1=577952742200569520, 
_param_0=577952226804494000) at /home/grahams/local/dmd2/linux/bin/../../
src/phobos/std/concurrency.d:228
#9  0x08054c18 in _D3bob13do_schedulingFbS3std11concurrency3TidZv 
(done_tid=..., print_deps=false) at /home/grahams/source/squid/open/
bedrock/build-tool/util/bob.d:2127
#10 0x08067bfc in 
_D3std11concurrency35__T5spawnTbTS3std11concurrency3TidZ5spawnFPFbS3std11concurrency3TidZvbS3std11concurrency3TidZS3std11concurrency3Tid4execMFZv
 
(this=0xf7d27b80)
at /home/grahams/local/dmd2/linux/bin/../../src/phobos/std/
concurrency.d:154
#11 0x0806c00e in _D4core6thread6Thread3runMFZv ()
#12 0x0807df2a in thread_entryPoint ()
#13 0xf7faa96e in start_thread (arg=0xf7521b70) at pthread_create.c:300
#14 0xf7ef3b5e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:130


Re: dcollections 1.0 and 2.0a beta released

2010-05-19 Thread Graham St Jack
While I haven't read dcollections yet, I definitely agree with you about 
not liking container hierarchies, and about the importance of support for 
ranges.

I hope Steven can be convinced that this is a good way to go :-).


Re: Concurrency architecture for D2

2010-01-03 Thread Graham St Jack
On Sun, 27 Dec 2009 14:32:52 -0600, Andrei Alexandrescu wrote:

 I think we are now in the position of defining a solid set of
 concurrency primitives for D. This follows many months of mulling over
 models and options.
 
 It would be great to open the participation to the design as broadly as
 possible, but I think it's realistic to say we won't be able to get
 things done on the newsgroup. When we discuss a topic around here,
 there's plenty of good ideas but also the inevitable bikeshed
 discussions, explanations being asked, explanations being given, and
 other sources of noise. We simply don't have the time to deal with all
 that - the time is short and we only have one shot at this.
 
 That's why I'm thinking of creating a mailing list or maybe another
 group for this. Any ideas on what would be the best approach? I also
 want to gauge interest from threading experts who'd like to participate.
 Please advise: (a) whether you would like to participate to the design;
 (b) keep discussions on the general group; (c) create a separate
 newsgroup; (d) create a mailing list. The latter would have open
 enrollment.
 
 
 Andrei

I would love to be involved too.


Re: TDPL goes out for preliminary review

2009-12-17 Thread Graham St Jack
On Thu, 17 Dec 2009 03:04:59 +, Graham St Jack wrote:

 On Thu, 17 Dec 2009 01:13:36 +0100, grauzone wrote:
 
 Andrei Alexandrescu wrote:
 But let's not forget we have concurrency ahead of us. I encourage you
 all to chime in with your thoughts and ideas regarding all aspects of
 concurrency. The recent multicore performance bug is a great starting
 point. If you try e.g. shared and it's broken, let us know. If you try
 it and it works, push it til it breaks. If you have ideas on how to
 make semantic checking better, pipe up.
 
 There's a guy on the NG who posts once in a while how broken shared is
 and how he has to use __gshared instead. His threads are being pretty
 much ignored.
 
 And now?
 
 
 Andrei
 
 I'm certainly in that category. I will be trying (soon) to put a post
 together that sets out my issues with 'shared'.

Here is my attempt to set out my problems with the shared keyword as it 
now stands.


First the good part: writing multi-threaded programs is not easy, and 
anything the language and compiler can do to make it easier is good.

Now for the way I approach writing multi-threaded programs:

Keep threads apart from each other wherever possible. Specifically, don't 
let them access or modify the same data except in well-understood and 
carefully controlled ways.

My preferred way of doing this is for threads to share only a very small 
amount of data, all of which is mutex protected, and carefully designed 
to be safe to access by multiple threads. My favourite kind of these is a 
templated queue (like a go channel). Any data passed out from such a 
shareable object has to be either immutable or cloned, so that each 
thread can rely on its data not being trampled on by other threads.

And my wish-list:

What I would like is for D to provide a clean way for me to be able to 
say this object and all its methods are nice and safe to access from 
multiple threads, and to also say all instances of this type are 
immutable.

And I also want the compiler to tell me if it thinks I have multiple 
threads accessing data in an unsafe way. 


Finally my issues with D as it stands:

Immutable or const objects are a real pain because I can't have a mutable 
reference to them. Rebindable doesn't seem to work, and I haven't been 
able to make a version that works well enough.

Immutable types don't add any value because you have to keep stating that 
objects of them are immutable everywhere. Having first-class immutable 
types would make it MUCH easier to reap the benefits of immutable data.

I can't currently see a use for the shared keyword as it stands. It seems 
to me that what is needed is a keyword more like shareable, meaning 
that this object (or data or function?) can be safely accessed by 
multiple threads. It should be an error to access a non-shareable object 
with multiple threads.

It should also be an error to claim that something is shareable unless it 
meets some well thought out criteria that the compiler can check. I 
haven't thought these out yet, but some candidates I like the look of are:
* All outputs from the object must be immutable or passed by value 
(cloned).
* All externally accessible methods must be synchronized on the object's 
monitor.

I'm happy that some sort of back-door override like __gshared has to be 
there for those cases that are actually ok, but only because of some 
grubby detail that the compiler can't figure out.


Re: TDPL goes out for preliminary review

2009-12-16 Thread Graham St Jack
On Thu, 17 Dec 2009 01:13:36 +0100, grauzone wrote:

 Andrei Alexandrescu wrote:
 But let's not forget we have concurrency ahead of us. I encourage you
 all to chime in with your thoughts and ideas regarding all aspects of
 concurrency. The recent multicore performance bug is a great starting
 point. If you try e.g. shared and it's broken, let us know. If you try
 it and it works, push it til it breaks. If you have ideas on how to
 make semantic checking better, pipe up.
 
 There's a guy on the NG who posts once in a while how broken shared is
 and how he has to use __gshared instead. His threads are being pretty
 much ignored.
 
 And now?
 
 
 Andrei

I'm certainly in that category. I will be trying (soon) to put a post 
together that sets out my issues with 'shared'.


Re: TDPL goes out for preliminary review

2009-12-16 Thread Graham St Jack
On Thu, 17 Dec 2009 00:51:48 +, dsimcha wrote:

 == Quote from Andrei Alexandrescu (seewebsiteforem...@erdani.org)'s
 article
 But let's not forget we have concurrency ahead of us. I encourage you
 all to chime in with your thoughts and ideas regarding all aspects of
 concurrency. The recent multicore performance bug is a great starting
 point. If you try e.g. shared and it's broken, let us know. If you try
 it and it works, push it til it breaks. If you have ideas on how to
 make semantic checking better, pipe up.
 Andrei
 
 I think for this to happen, there needs to be a tutorial somewhere
 explaining what shared is supposed to do (there were so many ideas
 thrown around that I don't remember them all and don't know which ones
 got adopted), and how much of it is already implemented.

I agree. The whole thing is very confused right now, and certainly 
everything I try in my code doesn't work out. The only way I can use 
threads tight now is to avoid use of shared at all. If anyone knows how 
it is supposed to work now, please write out a description.



Re: Various shared bugs

2009-12-08 Thread Graham St Jack
On Mon, 07 Dec 2009 22:45:17 -0500, Jason House wrote:

 So, after months of avoiding shared, I decided to see if I could remove
 all my casting away of shared.  It looks like things are still pretty
 buggy (or at least not particularly easy to use).
 
 is(T : shared) gives a parse error
 alias shared T U silently does the wrong thing.
(Use alias shared(T) U instead)
  is not callable using argument types () is just awful. 
 Typically, it means you're calling a non-shared function with a shared
 type or a shared function with a non-shared type.  I hit into a case
 where I got that message with a shared type and a shared method, but I
 have mad no attempt to reproduce.
 The error Can not implicitly convert expression of type(this) of type
 shared(xxx) to full.name.xxx can pop up when defining shared this()
 constructor gives no line number where the offending usage occurs.
 
 I've backed out most of my pro-shared changes and will try again in a
 few months :(

I have also given up on shared and am also adopting a waiting strategy.

I would love to get some tips from anyone (like Walter, for example) who 
thinks they have a way of using shared successfully.

My recent post on the subject got no meaningful responses - just one from 
bearophile that was supportive, but alas not helpful.


Ongoing problems with shared and immutable

2009-11-26 Thread Graham St Jack
I have been dabbling with the shared and immutable keywords in an effort 
to find out if they are usable, and aren't getting anywhere. My current 
code base avoids them like the plague, but I can see the advantages of 
them if only they were usable.

The previous newsgroup threads on this issue have all petered out without 
any resolution.

Here is a small program that shows the sort of thing I am trying to do. 
There is nothing tricky here, just passing of immutable data via a shared 
queue between what could be two threads.



import std.typecons;


// immutable message
immutable class Message {
public int data;

this(int value) {
data = value;
}
}


// Queue-like shared synchronized container.
// The Condition on remove() is missing for brevity. 
shared class Queue {
private Rebindable!(Message) mMsg;

this() {
mMsg = null;
}

synchronized void add(Message msg) {
mMsg = msg;
}
synchronized Message remove() {
return mMsg.get;
}
}


int main(string args[]) {
// pretend to be one thread queuing an object
auto queue = new Queue();
auto tx_message = new Message(1);
queue.add(tx_message);

// pretend to be another thread taking the data.
auto rx_message = queue.remove;
return rx_message.data;
}



Here are the error messages when I compile it with dmd 2.036:

Error: cannot implicitly convert expression (this) of type immutable
(Message) to shared_problem.Message
shared_problem.d(22): Error: function std.typecons.Rebindable!(immutable
(Message)).Rebindable.opAssign (immutable(Message) another) is not 
callable using argument types (void*) shared
Error: cannot implicitly convert expression (this) of type shared(Queue) 
to shared_problem.Queue
shared_problem.d(26): Error: function std.typecons.Rebindable!(immutable
(Message)).Rebindable.opAssign (immutable(Message) another) is not 
callable using argument types (immutable(Message)) shared
shared_problem.d(29): Error: struct std.typecons.Rebindable!(immutable
(Message)).Rebindable member original is not accessible
shared_problem.d(29): Error: struct std.typecons.Rebindable!(immutable
(Message)).Rebindable member original is not accessible


Apart from annoyances like not getting a line number on some of the 
errors, it looks like:

immutable types (at least for classes) aren't usable.

shared seems to be applied to immutable variables when it shouldn't, 
confusing the type system.

shared types don't seem to be usable.

Rebindable seems to be broken.


Note that I'm trying to use immutable and shared types in the hope that I 
can then avoid having to declare the instances of them as being immutable 
or shared everywhere. In any case, they are in the documentation, so they 
should work ;-).

Does anyone have an approach that works without bypassing shared and 
immutable completely?


Re: Condition Mutexes

2009-10-20 Thread Graham St Jack
On Wed, 21 Oct 2009 00:56:13 +, dsimcha wrote:

 I'm messing around w/ core.sync.  Does anyone know what I'm doing wrong
 in this program?  It just hangs. If I could figure out ()##$) condition
 mutexes (right now, I'm using busy spinning), I might have a decent
 implementation of parallelForeach over ranges.
 
 import core.sync.mutex, core.sync.condition, core.thread, std.stdio;
 
 __gshared Condition condition;
 
 void waitThenPrint() {
 condition.wait();
 writeln(FOO);
 }
 
 void main() {
 condition = new Condition( new Mutex() ); auto T = new
 Thread(waitThenPrint);
 T.start();
 condition.notify();  // Never wakes up and prints FOO.
 }

There are a few problems. The most serious is that you have to lock the 
mutex before calling condition.wait(). The underlying operating-system 
stuff atomically 

This means that the mutex needs to be an attribute of the class, and 
waitThenPrint() should be more like this:

void waitThenPrint() {
  synchronized(myMutex) {
condition.wait();
  }
  writeln(FOO);
}

While it isn't strictly necessary in this case, you should also:

Put the condition.notify() call into a synchronized(myMutex) block.

When some state variables are involved in the condition, you should do 
something like this:

void waitThenPrint() {
  synchronized(myMutex) {
while (state_not_right()) {
  condition.wait();
}
  }
  writeln(FOO);
}

and

synchronized(myMutex) {
  set_state_to_right();
  condition.notify();
}


Re: Phobos.testing

2009-10-11 Thread Graham St Jack
This discussion is great news. I will happily contribute to Phobos if the 
barriers are lowered enough. It would be worthwhile posting something on 
the announce newsgroup when you have some sort of improved contribution 
procedure worked out.

Also, I would be happier with mercurial or git than with subversion.


Re: It's official: One-day D tutorial at the ACCU Conference 2010 in Oxford, England

2009-10-01 Thread Graham St Jack
I would love to get my hands on the transcript and video of the event...
Will it be recorded?


Re: It's official: One-day D tutorial at the ACCU Conference 2010 in Oxford, England

2009-10-01 Thread Graham St Jack
I would love to get my hands on the transcript and video of the event...
Will it be recorded?


Re: shared adventures in the realm of thread-safety.

2009-09-16 Thread Graham St Jack
On Wed, 16 Sep 2009 08:00:40 -0400, Jason House wrote:

 Graham St Jack Wrote:
 
 So, what is the design of shared supposed to be then? Its time for
 Walter to buy in and tell us where this is all going - I for one am
 very confused right now.
 
Thanks for that. Its good to know that there is a plan in there 
somewhere, even if the details are still very fuzzy. I agree that the 
lofty goal of improving thread-safety for mere mortals is worthwhile, and 
that it won't be easy to pull off.

What I was really after though is what the plan is for D2 right now. The 
whole shared situation in D2 looks like a mess to me, and I would like 
some reassurance that something simple and tidy will be happening soon.



 Here's what I know:
 • Bartosz's ownership scheme is delayed until at least D3 • Shared 
code
 will be sequentially consistent • Walter likes the idea of optimizing
 away memory barriers that the compiler can prove are unneeded (some
 barriers in synchronized sections) • Bartosz is rewriting how threads
 are done similar to what his blogs hint at • Issues that Bartosz hits
 with shared are fixed immediately
 
 Here's what I suspect from a number of emails: • Because every class
 contains a monitor, Walter/dmd will treat every class as its own monitor
 for the purposes of optimization.
 
 I too wish Walter would advertise the design, but I think the simple
 fact is that he doesn't know what the design is!



Re: shared adventures in the realm of thread-safety.

2009-09-15 Thread Graham St Jack
So, what is the design of shared supposed to be then? Its time for Walter 
to buy in and tell us where this is all going - I for one am very 
confused right now.

Currently I am working around it by not using synchronized methods (I put 
synchronized blocks inside the methods), which is very bad form, but what 
else can I do?


Re: shared adventures in the realm of thread-safety.

2009-09-12 Thread Graham St Jack
I'm also having the same problems.

As Jeremie said, as soon as you start introducing shared methods (via 
synchronized for example), you rapidly get into trouble that can only be 
overcome by excessive casting.

It may be possible to contain the problem by refactoring multi-threaded 
code so that the shared objects are very small and simple, but even then 
the casting required is too much. This approach might be ok if you could 
define classes as being shared or immutable, and ALL instance of them 
were then implicitly shared or immutable. Also, immutable objects should 
be implicitly shareable.


On Sat, 12 Sep 2009 15:32:05 -0400, Jason House wrote:

 I'm glad to see I'm not the only one trying to use shared. I tried to
 use it with 2.031 and rapidly hit bug after bug... I submitted several
 bug reports for basic functionality, and none of it appeared in the
 changelog.
 
 http://d.puremagic.com/issues/show_bug.cgi?id=3089
 http://d.puremagic.com/issues/show_bug.cgi?id=3090
 http://d.puremagic.com/issues/show_bug.cgi?id=3091
 
 
 
 Jeremie Pelletier Wrote:
 
 I decided to play once again with shared and see what 2.032 is capable
 of. Turns out a lot of the previous issues I was having last time are
 gone, however, there are still a few things left which prevent me from
 rewriting my code.
 
 The first issue that jumped to my face straight away was how 'shared
 const' methods are not callable from 'shared' objects.
 
 shared class Foo {
  void bar() const;
 }
 auto foo = new Foo; // foo is of type shared(Foo) foo.bar; //  Error:
 function Foo.bar () shared const is not callable using argument types
 () shared
 
 Considering how 'const' methods can be called from mutable objects,
 this looks like either a bug or a really awkward feature to me. Sending
 a shared(Foo) to a method expecting a shared(const(Foo)) also triggers
 a similar error from the compiler.
 
 The other issue may be an intended feature, but it doesn't sound
 practical to me. Marking a method as shared assumes all used properties
 in the method's scope are also shared. Here is an example to illustrate
 my point:
 
 class SimpleReader {
this(LocalFile file) { _stream = new FileInputStream(file); } ...
 private:
 synchronized void read(ubyte[] buf, long offset) {
 _stream.seek(offset);
 _stream.read(buf);
 }
 FileInputStream _stream;
 }
 
 The FileInputStream here is a generic blocking binary stream which is
 not thread-safe by design. The reader is a composite class where every
 instance has its own unique stream instance and use it to implement
 asynchronous reads over the file format it abstracts, which in my case
 is a specialized read-only archive using a lot of random accesses from
 different threads.
 
 This is where the issue shows its ugly head. The 'synchronized' keyword
 tags the read method as shared, which in itself is quite neat, what is
 annoying however is that it also changes the type of _stream in the
 method's scope to shared(FileInputStream) and therefore triggers
 compiler errors because _stream.seek and _stream.read are not shared:
 
 Error: function FileInputStream.read (ubyte[]) is not callable using
 argument types (ubyte[]) shared
 
 While it may be an attempt to keep shared usage safe, it isn't very
 practical. The stream object here is not shared because it is not
 thread-safe. While it may be used by different threads, it is unique to
 the reader's context and its accesses are synchronized by the reader,
 the stream should therefore be completely oblivious to the fact it is
 being used by different threads.
 
 Maybe this could be the time to implement an unique qualifier; this is
 a context where having _stream be of type unique(FileInputStream) would
 solve the problem and allow further compiler optimizations. I don't
 know if it can be done with templates, and without any overhead
 whatsoever. I know I would much rather see unique(Foo) than Unique!Foo,
 and it would allow the use of 'is(foo : unique)'.
 
 Furthermore, tagging a method with shared does not make it thread-safe,
 it may however use synchronized within its scope to protect its shared
 or unique data. This may be confusing when calling shared methods vs
 calling synchronized methods; one may think the shared one is not
 thread-safe and optionally synchronize the call, resulting in another
 monitor being used for nothing, or no monitor being used at all:
 
 class Foo {
 shared void bar() {
 // Do stuff with local or immutable data synchronized(this) {
 /* do stuff with shared data */ }
 }
 shared void bar2() {
 // Do stuff on shared data
 }
 }
 
 Someone seeing only the prototype of Foo.bar may assume the method is
 not thread-safe and call it as 'synchronized(foo) foo.bar()'. Just like
 they could see the prototype of bar2 and assume it is thread-safe,
 calling it as 'foo.bar2()'.
 
 What could be a good design against this sort of misleading behavior?
 
 Phew, that's about 

Re: dmd 1.047 and 2.032 releases

2009-09-06 Thread Graham St Jack
Its great to see so many bugs being sorted out.

However, I am having all kinds of trouble with shared, which up until 
now I have been able to fairly easily sidestep. Here is a cut-down 
example of what I am trying to do, which is to have one thread acquiring 
data and passing it on to another thread via a queue which uses 
appropriate synchronization mechanisms to make things thread-safe. The 
data passed through is immutable, so theoretically everything should be 
fine.

This kind of thing is very routine in multi-threaded programs, and should 
be easy to pull off. I find I have to do heaps of nasty casting to get 
past the compiler (the immutable assignment thing is a side issue).

Is there a neater syntax for this? How about being able to say shared 
immutable class Message {...} (or just shared or just immutable or just 
const), and then all instances (new, local, parameter, return) would 
automatically be shared and immutable?


class Message {
int data_;
this(int value) {
data_ = value;
}
int get() immutable {
return data_;
}
}

// queue-like synchronized container
class Queue {
immutable(Message) msg_;

this() {
msg_ = null;
}

synchronized void add(immutable(Message) msg) {
Message * tmp = cast(Message *) msg_;
*tmp = cast(Message) msg;
}
synchronized immutable(Message) remove() {
return msg_;
}
}


int main(string args[]) {
// pretend to be one thread queueing an object
auto queue = cast(shared) new Queue();
auto message = cast(immutable) cast(shared) new Message(1);
queue.add(message);

// pretend to be another thread taking the data and working with it
return queue.remove.get;
}



Re: const and immutable objects

2009-09-01 Thread Graham St Jack
On Mon, 31 Aug 2009 15:20:21 -0500, Andrei Alexandrescu wrote:

 Graham St Jack wrote:
 I have been trying (again) to start using const and immutable objects
 in a project, and found I kept getting stuck with the need to change
 the value of object references, which isn't allowed. I don't quite
 follow the arguments that mean that this has to be the case, but I'm
 prepared to accept them.
 
 After some experimenting with Andrei's Rebindable template, I still
 couldn't get past the problems. For a start, the get method is private
 so I couldn't test for null.
 
 In the end I cooked up the following, which is a very simple workaround
 that just lets me assign to a const or immutable object reference. It
 works just fine, and can be used in templates like containers without
 forcing the container to care about what it is containing.
 
 Comments?
 
 [snip code]
 
 Hi Graham,
 
 Could you please post a short snippet (or a few) that illustrate the
 problems you ran into with Rebindable?
 
 
 Thanks,
 
 Andrei

The code fragments are lost in the sands of time - I can recreate them if 
necessary, but here is an outline of what the problems were:

Rebindable!(Foo) foo = null;
foo = cast(immutable) new Foo(); // ok so far
foo = Foo.init;  // still ok
if (foo !is null) {} // compiler error
if (foo.get !is null) {} // another compiler error, and nasty!

The main thing that has to change in Rebindable is that it needs to be a 
transparent wrapper, so that if (foo !is null) {} works.


What I was doing to get into trouble was writing some communications code 
using Fibers, and I wanted the message objects to be immutable (call me 
silly, but I wanted to give it a go). This meant I needed to:

* Have a templated queue class that could contain any sort of mutable 
types, and const or immutable objects. In particular, I didn't want the 
queue to have to use different code for objects and (say) integers.

* Pass messages between the Fibre's stack frame and the main thread, so 
for an immutable object reference I needed to: test for null, assign to 
null and assign to a new message.

The motivation for passing immutable messages around is that there is an 
implicit assumption that these messages don't mutate as they fan out to 
various destinations, and I wanted some compiler enforcement.


Re: const and immutable objects

2009-08-31 Thread Graham St Jack
On Mon, 31 Aug 2009 09:12:33 -0400, Steven Schveighoffer wrote:

 On Sun, 30 Aug 2009 18:31:33 -0400, Graham St Jack
 graham.stj...@internode.on.net wrote:
 
 I have been trying (again) to start using const and immutable objects
 in a project, and found I kept getting stuck with the need to change
 the value of object references, which isn't allowed. I don't quite
 follow the arguments that mean that this has to be the case, but I'm
 prepared to accept them.

 After some experimenting with Andrei's Rebindable template, I still
 couldn't get past the problems. For a start, the get method is private
 so I couldn't test for null.

 In the end I cooked up the following, which is a very simple workaround
 that just lets me assign to a const or immutable object reference. It
 works just fine, and can be used in templates like containers without
 forcing the container to care about what it is containing.

 Comments?
 
 First, a little history lesson.  An earlier version of const had this
 distinction:
 
 class C {}
 
 const(C) c; // c is rebindable, what it points to is const
 
 const C c2; // c2 is not rebindable.
 
 The const(C) format was modeled after pointers and arrays, i.e.
 const(C)[] and const(C)*, but since the reference is not explicitly
 stated, it's invisible in the const format also :)
 
 So that was thrown out because it was determined that const(...) should
 mean that anything inside the parentheses should be const (including a
 class reference).  What followed was several attempts (including some by
 me) to come up with a way to denote a tail-const class reference.  Most
 of them centered around pulling out the reference part, i.e. ref
 const(C) or const(*C)*.  Others included new keywords.  In the end, none
 of them looked great, and none of them made Walter change his mind.  So
 via syntax, there is no way to say rebindable reference to const class
 data.  So to answer your first question, there's no objection by Walter
 and crew as to being able to rebind a const class reference, there's
 just no good syntax to denote it (that has been presented so far
 anyways).
 
 Then Andrei came along with Rebindable, and the argument died down.  I
 had a feeling that Rebindable would be somewhat unusable in its current
 form, but given that we were about to get opImplicitCast and other
 niceties, it seemed Rebindable would be sufficient in the future.
 
 OK, so now we have alias this which is supposed to be the implementation
 of opImplicitCast, and you say it's still too difficult.  Looking at the
 source, it looks like Rebindable needs some attention, as it still
 doesn't use alias this.  I have no idea if there is a way to implement
 !is null, but I assume that it should be forwarded to the alias this
 member.
 
 So I think a bug report is in order.  Rebindable should not use opDot,
 but rather alias this.  Implicit casting is paramount to make Rebindable
 look like a transparent wrapper.
 
 -Steve

I remember the history - it was long and complicated, with no answer that 
looked good. I also agree that Rebindable as it stands needs work, and 
definitely needs to be a transparent wrapper. Since I don't understand 
the issues all that well, how about you submit the bug report?


const and immutable objects

2009-08-30 Thread Graham St Jack
I have been trying (again) to start using const and immutable objects in 
a project, and found I kept getting stuck with the need to change the 
value of object references, which isn't allowed. I don't quite follow the 
arguments that mean that this has to be the case, but I'm prepared to 
accept them.

After some experimenting with Andrei's Rebindable template, I still 
couldn't get past the problems. For a start, the get method is private so 
I couldn't test for null.

In the end I cooked up the following, which is a very simple workaround 
that just lets me assign to a const or immutable object reference. It 
works just fine, and can be used in templates like containers without 
forcing the container to care about what it is containing.

Comments?

//
// Assign dest to src, using brute-force methods as necessary if T
// is an immutable or const object.
//
// The intent is to avoid needing routine nasty tricks in
// application code, especially in template code which should be
// spared the complication of handling this very annoying
// restriction on objects. Use of this template function doesn't
// let you change the object itself, just the reference to it - so
// all should be well.
//
void forcefulAssign(T)(ref T dest, T src) {
static if (!is(T X == const(U), U)   !is(T X == invariant(U), U)) {
// T is not const or immutable - just assign normally
dest = src;
}
else static if (is(T : Object)) {
// T is a const or immutable object - use brute force
U * ptr = cast(U *) dest;
*ptr = cast(U) src;
}
else {
// T is some other const or immutable type - not assignable
static assert(false, cannot assign to  ~ T.stringof);
}
}

// assign the default initializer to something
void forcefulInitialize(T)(ref T dest) {
static if (!is(T X == const(U), U)   !is(T X == invariant(U), U)) {
// T is not const or immutable - just initialise normally
dest = T.init;
}
else static if (is(T : Object)) {
// T is a const or immutable object - use brute force
U * ptr = cast(U *) dest;
*ptr = U.init;
}
else {
// T is some other const or immutable type - not assignable
static assert(false, cannot assign to  ~ T.stringof);
}
}



Re: const and immutable objects

2009-08-30 Thread Graham St Jack
On Sun, 30 Aug 2009 21:28:18 -0400, Jeremie Pelletier wrote:


 I agree that D lacks a mechanism to separate the object from it's
 reference. Maybe syntax like the following could be used to apply the
 storage class to the object value, and not the reference value:
 
 class Foo;
 void bar(in Foo foo) {}
 
 It's quite ugly and C-like, but that's the first thing that came to
 mind. The reference value is unique to the current method and shouldn't
 share the same storage qualifiers as it's referenced memory.

I think the time for pining over this particular syntax feature of D is 
over - as nice as it would be to be able to fix the problem in the 
language, it would be too disruptive right now. What we need is something 
in phobos that works around the problem, and Rebindable isn't suitable as 
it stands because:

* It presents different interfaces for different kinds of wrapped types.
* It doesn't let you access the wrapped object except via opDot.

My suggested workaround is perhaps a bit rough, but it does work. I would 
like to hear from anyone who is using const and immutable objects in D2 
who has something better, or has suggestions to improve my code.


Re: T[new]

2009-08-10 Thread Graham St Jack
This sounds excellent.


Re: project oriented

2009-05-15 Thread Graham St Jack
On Tue, 12 May 2009 21:12:51 +, BCS wrote:

 Hello davidl,
 
 The module package system still stays in the state of the C age. It's
 file  oriented. I think there's no more sound package system than C#
 one. The  namespace and distributed packaging is a must nowadays and
 the compiler  should be project oriented and take project information
 as the compiling  base. Also an IDE is quite useful for providing
 project templates.
 
 
 The up side to file based packaging is that the compiler can find the
 files without needing extra information. There are several tools that
 can build a project from nothing but a set of .d files. With the c# type
 of system, the compiler/build system needs to have a metadata file that
 list all the .d files to be built adding yet another piece of redundant
 complexity.
 
 The c# solution works well if you will *only* develop from the IDE but
 is a total pain as soon as you need to work with non-language aware
 tools.

Good point. I like the current system's simplicity, and changing it as 
suggested would add a lot of hassle.


Re: When will D1 be finished?

2009-05-11 Thread Graham St Jack
On Mon, 11 May 2009 12:11:53 -0700, Walter Bright wrote:

 Luís Marques wrote:
 When D1 was declared finished I thought it meant it would progress to a
 stable state, with nearly all non-minor problems fixed and a large set
 of companion libraries. I'm afraid I don't see that happening at an
 animating rate.
 
 D1 regularly gets around 20 bug fixes a month. I don't understand why
 this is not seen as progress to a stable state. About 80% of bug fixes
 are common to both D2 and D1.

I agree that D1 is getting its fair share of attention, and I support the 
earlier post that suggested getting in there and making contributions 
yourself if you don't like the rate of progress in your personal area of 
interest.

D (especially D2 ;-) ) is far and away the best language I have ever 
worked with already, and I think the team needs to be congratulated for 
its efforts. I'm embarrassed that I can't contribute more because of 
other commitments, but when I do, it is done as constructively as 
possible.


Re: Weird std.stdio threading bug?

2009-04-30 Thread Graham St Jack
I posted a bug report for this a few days ago (2890). I got as far as 
finding out that it is a file locking problem caused by what looks like a 
compiler bug re calling the destructor of a struct. The following patch 
to std.stdio works around the problem, but is hardly a fix.

$ diff dmd/src/phobos/std/stdio.d stdio.d
922c922
 //return LockingTextWriter(this);
---
 return LockingTextWriter(this);
925,926c925,926
 auto result = LockingTextWriter(this);
 return result;
---
 //auto result = LockingTextWriter(this);
 //return result;




On Mon, 27 Apr 2009 22:53:04 +, dsimcha wrote:

 The following small test program seems to have a weird deadlock or
 something:
  It should keep printing the phrase Doing stuff. forever, but it only
  gets
 through maybe two iterations before its CPU usage does to zero and it
 stops printing, at least on my computer.  Has anyone noticed any bad
 behavior with std.stdio and multithreading?
 
 import core.thread, std.stdio;
 
 void main() {
 Thread[] myThreads;
 foreach(i; 0..4) {
 myThreads ~= new Thread( { doStuff(); }); myThreads[$ -
 1].start;
 }
 }
 
 
 
 void doStuff() {
 while(true) {
 synchronized {
 writeln(Doing stuff.);
 }
 }
 }
 
 
 If the writeln line is commented out, this thing keeps executing the
 empty loop with measurable CPU usage.



Re: Bug in std.socket

2009-04-15 Thread Graham St Jack
On Wed, 15 Apr 2009 00:38:33 -0700, Unknown W. Brackets wrote:

 Does waiting for a keypress in the client thread do you any favors?
 
 Also, you can get some mileage by doing a select() (see SocketSet) on
 the socket first.  This will tell you if you need to accept(), and also
 allow you to do timeouts.  I'm a big fan of non-blocking sockets, you
 can improve connect() this way too.
 
 -[Unknown]


Thanks for all the useful suggestions. I'm on the ticket bandwagon at 
last.

I realise that the code I posted was a bit rough (although I missed the 
race, which is definitely there). It was a heavily cut-down version of 
something a lot larger that does indeed use select, uses non-blocking I/
O, retries connection attempts, and even uses Fibers. What I wanted was a 
small and simple test case to attach to the ticket, not something serious.


Re: Bug in std.socket

2009-04-15 Thread Graham St Jack
On Wed, 15 Apr 2009 09:35:45 -0700, Brad Roberts wrote:

 Graham St Jack wrote:
 On Wed, 15 Apr 2009 00:38:33 -0700, Unknown W. Brackets wrote:
 
 Does waiting for a keypress in the client thread do you any favors?

 Also, you can get some mileage by doing a select() (see SocketSet) on
 the socket first.  This will tell you if you need to accept(), and
 also allow you to do timeouts.  I'm a big fan of non-blocking sockets,
 you can improve connect() this way too.

 -[Unknown]


 Thanks for all the useful suggestions. I'm on the ticket bandwagon at
 last.
 
 I realise that the code I posted was a bit rough (although I missed the
 race, which is definitely there). It was a heavily cut-down version of
 something a lot larger that does indeed use select, uses non-blocking
 I/ O, retries connection attempts, and even uses Fibers. What I wanted
 was a small and simple test case to attach to the ticket, not something
 serious.
 
 I was about to close the ticket as invalid due to buggy reproduction
 code.  Can you demonstrate the problem with an example app that's _not_
 buggy?  If so, please attach it to the bug report.
 
 Later,
 Brad

Someone else already provided a much simpler test case without bugs.


Bug in std.socket

2009-04-14 Thread Graham St Jack
Forgive my ignorance, but can anyone tell me how to post a ticket for 
phobos?

I want to report a bug in std.socket's TcpSocket.accept() (at least it 
manifests itself there for me) introduced in D 2.0.27 and still there in 
2.0.28. The following code runs to completion in 2.026 and blocks on 
accept in later compiler versions.


import std.socket;
import std.stdio;
import core.thread;


class Server {
private {
InternetAddress mAddress;
Thread  mThread;
}

this(InternetAddress address) {
mAddress = address;
mThread  = new Thread(run);
mThread.name = server.dup;
mThread.start;
}

void join() {
mThread.join;
}

void run() {
try {
writefln(server - setting up server socket);
auto listener = new TcpSocket();
listener.bind(mAddress);
listener.listen(5);

// wait for a connection
writefln(server - waiting for a client connection);
auto socket = listener.accept();
writefln(server - got a client connection);

// read some data and write it back
writefln(server - reading data from the client);
ubyte[100] data;
int qty = socket.receive(data);
writefln(server - writing the data back to the client);
socket.send(data[0..qty]);
}
catch (Exception ex) {
writefln(server - server got exception: %s, ex);
}

// terminate
writefln(server - terminating);
}
}

class Client {
private {
InternetAddress mAddress;
Thread  mThread;
}

this(InternetAddress address) {
mAddress = address;
mThread = new Thread(run);
mThread.name = client.dup;
mThread.start;
}

void join() {
mThread.join;
}

void run() {
try {
// connect
writefln(client - connecting to server);
auto socket = new TcpSocket(mAddress);
writefln(client - connected to server);

// send and receive some data
writefln(client - sending data to server);
ubyte[3] send_data;
send_data[0] = 41;
send_data[1] = 42;
send_data[2] = 43;
int qty = socket.send(send_data);
assert(qty == send_data.length);
writefln(client - receiving data from server);
ubyte[100] receive_data;
qty = socket.receive(receive_data);
writefln(client - got %s bytes from server, qty);
}
catch (Exception ex) {
writefln(client - client got exception %s, ex);
}

// terminate
writefln(client - terminating);
}
}



int main(string[] args) {
writefln(test starting);

try {
InternetAddress address = new InternetAddress(localhost, 12345);
Server server = new Server(address);
Client client = new Client(address);
writefln(joining with server);
server.join;
writefln(joining with client);
client.join;
writefln(finished);
}
catch (Exception ex) {
writefln(unexpected exception %s, ex);
}
return 0;
}


Re: Proposal: adding condition variable to object monitors

2009-03-20 Thread Graham St Jack


 class C
 {
  Mutex m;
  Condition c;

  this()
  {
  // make m this object's monitor
  m = new Mutex( this );
  c = new Condition( m );
  }

  synchronized void foo()
  {
  // m is locked
  c.notify();
  }
 }
 

I like this approach, and agree that it is very useful to be able to have 
more than one condition share the same mutex.

I don't mind the handraulic creation of the mutex and condition when you 
are using a condition, because of the added flexibility and the fact that 
it doesn't come up much.

Being able to use the Object's monitor for the mutex is really good too.

Please release it soon!


Re: dmd platform support - poll

2009-01-04 Thread Graham St Jack
On Thu, 25 Dec 2008 15:56:29 -0800, Sean Kelly wrote:

 Walter Bright wrote:
 What platforms for dmd would you be most interested in using?
 
 In order of preference:
 
 mac osx 32 bit intel
 linux 64 bit
 mac osx 64 bit intel

Ditto


Re: DMD 1.036 and 2.020 releases

2008-10-21 Thread Graham St Jack
On Mon, 20 Oct 2008 16:29:36 -0700, Walter Bright wrote:

 http://www.digitalmars.com/d/1.0/changelog.html
 http://ftp.digitalmars.com/dmd.1.036.zip
 
 The 2.0 version splits phobos into druntime and phobos libraries (thanks
 to Sean Kelly). This will enable both Tango and Phobos to share a common
 core library.
 
 http://www.digitalmars.com/d/2.0/changelog.html
 http://ftp.digitalmars.com/dmd.2.020.zip
 
 There are a lot of structural changes that go along with this, so expect
 some rough patches with this release. It may take a followup release to
 file them down. There's also some renaming of imports and function
 names, as a compromise with Tango names.

This is FANTASTIC news. Many thanks to everyone involved, especially Sean 
for all the hard work.