Immutability, problems with debugging

Timon Gehr timon.gehr at gmx.ch
Fri Feb 17 05:14:42 PST 2012


On 02/17/2012 11:51 AM, Nathan M. Swan wrote:
> I'm working on a novice solver of the travelling salesman problem, and
> when I decided to go concurrent I had to make everything immutable. Now
> this happens:
>
> /usr/share/dmd/src/phobos/std/format.d(1782): Error: function
> object.Object.toString () is not callable using argument types () immutable
>
> Unfortunately, I don't know how format is called, so I can't investigate
> closer. Does anyone notice anything glaringly obvious?
>
> https://github.com/carlor/tsp.d/blob/master/tsp.d
>
> This brings up an issue that's happened before; there's an error in the
> semantics of a (usually generic) function call, and I don't know where
> the function is called. It would be nice if the compiler could do
> something like "mentioned on file1.d(33), mentioned on file2.d(107)".
>
> Thanks, NMS

Hi Nathan,

This kind of question usually is better placed in d.D.learn.
Anyway, the reason why your code does not work is because 
std.concurrency cannot yet deal with head-immutable data. (It will work 
as soon as these issues are fixed.) I have edited the code to a point 
where it compiles. (probably is also more efficient than before.) I hope 
I have preserved the semantics.

What version of the compiler are you using? I didn't get the error you 
describe.


/* tsp.d - a multithreading implementation of the traveling salesman problem
Copyright (C) 2012 Nathan M. Swan
See README for details.

tsp.d is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

tsp.d is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
module tsp;

import std.algorithm;
import std.array;
import std.concurrency;
import std.conv;
import std.exception;
import std.functional;
import std.math;
import std.stdio;

void main(string[] args) {
     try {
         enforce(args.length == 2, "must give city file");
         auto cities = readFromFile(args[1]);
         auto route = bestRouteBetween(cities[0], cities[0],
                                                  cities[1 .. $]);
         writeln("Distance: ", route.distance);
         foreach(city; route.cities) {
	        writeln(city.name);
         }
     } catch (Exception e) {
         stderr.writeln("Error: ", e.msg);
     }
}

immutable(City)[] readFromFile(string fname) {
	immutable(City)[] r;
     foreach(line; File(fname, "r").byLine()) {
         // get rid of comments
         line = findSplit(line, "#")[0];

         // put into three tokens
         auto tkrange = splitter(line, " ");
         string[] tokens = filterEmpties(tkrange);

         if (tokens.length == 0) continue;

         // construct city
         enforce(tokens.length == 3, "must be three tokens per line");
         r~=City(tokens[0],to!real(tokens[1]),to!real(tokens[2]));
     }
     return r;
}

// return the best route between the two cities containing the others
Route bestRouteBetweenFunc(City a,
                            City b,
                            immutable(City)[] others)
{
     if (others.length) {
         Route best = Route([], real.max);
         foreach(i, o; others) {
	        spawn(&brtWrapper, thisTid, b, i, cast()o, others);
         }
         foreach(i; 0 .. others.length) {
	        Route r = receiveOnly!(Route)();
             auto realdist = r.distance + distanceBetween(a, others[i]);
             if (realdist < best.distance) {
                 best = Route(a ~ r.cities, realdist);
             }
         }
         return best;
     } else {
         return Route([a, b], distanceBetween(a, b));
     }
}

// calls the bestRouteBetween function and notifies
void brtWrapper(Tid parent, // thread to alert of being done
                 City b, // the last chain member
                 size_t i, // index of o
                 City o, // o, the focused chain member
                 immutable(City)[] others) // the non-b chain members
{
     auto r = bestRouteBetween(o, b, others[0..i] ~ others[(i+1)..$]);
     parent.send(r);
}

real distanceBetweenFunc(City a, City b) {
     real xs = a.x - b.x;
     real ys = a.y - b.y;
     return sqrt(xs*xs + ys*ys);
}


string[] filterEmpties(T)(T range) {
     string[] r;
     foreach(str; range) {
         if (!str.empty) {
             r ~= str.idup;
         }
     }
     return r;
}

struct City {
     string name;
     real x;
     real y;
}

struct Route {
	this(immutable(City)[] c, real d) { cities = c; distance = d; }

	immutable(City)[] cities;
     real distance;
}

alias memoize!bestRouteBetweenFunc bestRouteBetween;
alias memoize!distanceBetweenFunc distanceBetween;


More information about the Digitalmars-d mailing list