www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opCmp with structs

reply Alex <sascha.orlov gmail.com> writes:
I'm sure I'm doing a silly mistake somewhere, but why this 
doesn't work?
import std.stdio;
import std.algorithm;

struct ku
{
	immutable int id;
	alias id this;
	
	this(int i)
	{
		id = i;
	}
	
	int opCmp(ref const ku rhs) const {return id - rhs.id; }
}

void main()
{
	ku[] tt = [ku(2), ku(1)];
	sort(tt);
}
Nov 06 2015
next sibling parent reply Alex <sascha.orlov gmail.com> writes:
Ok... the question is not silly any more...
without 'immutable' it works. So, what am I missing?
Nov 06 2015
next sibling parent BBaz <bb.temp gmx.com> writes:
On Friday, 6 November 2015 at 22:55:15 UTC, Alex wrote:
 Ok... the question is not silly any more...
 without 'immutable' it works. So, what am I missing?
sort() fails because in the template constraint `hasAssignableElements
Nov 06 2015
prev sibling parent reply BBaz <bb.temp gmx.com> writes:
On Friday, 6 November 2015 at 22:55:15 UTC, Alex wrote:
 Ok... the question is not silly any more...
 without 'immutable' it works. So, what am I missing?
sorry, again a forum bug that stripped my answer: sort() fails because in the template constraint `hasAssignableElements` fails. hasAssignableElements fails because of this you cannot assign another value to a ku because the immutable member is already defined. --- template hasAssignableElements(R) { enum bool hasAssignableElements = isInputRange!R && is(typeof( (inout int = 0) { R r = R.init; r.front = r.front; static if (isBidirectionalRange!R) r.back = r.front; static if (isRandomAccessRange!R) r[0] = r.front; })); } --- more especially this is 'r.front = r.front;' that doesn't pass: --- import std.range; struct ku { immutable int id; } void main() { ku[] tt; tt.front = tt.front; } --- so yeah, it cant work if id is immutable.
Nov 06 2015
parent reply Alex <sascha.orlov gmail.com> writes:
Ok, ok... I see the direction, but I still miss something:
 From the point of view of "Programming in D", chapter 33.3, 
"Immutability of the slice vs the elements":

I don't want to have an immutable slice but immutable elements. 
And your answers imply that sorting not only modify the slice 
itself but also mutate the elements. This is a little bit 
strange, in my opinion, as sorting modifies only relationships 
between the sorted elements not the elements itself. At least in 
my head, at least for the moment :)

A test says the same thing:

void main()
{
	immutable int[] immSlice = [2, 1];
	sort(immSlice);
}

and

void main()
{
	immutable(int)[] immSlice = [2, 1];
	sort(immSlice);
}

both give errors:
Error: template std.algorithm.sorting.sort cannot deduce function 
from argument types !()(immutable(int[]))
and
Error: template std.algorithm.sorting.sort cannot deduce function 
from argument types !()(immutable(int)[])
respectively.

So the question remains, how to sort? Do you think removing the 
immutable property from an id is the semantically right way? Or 
do you have a hint, maybe something like, a dup copy with 
removing immutability and returning a new, sorted copy? If you 
think the latter is the way to choose, how is the syntax there? ;)
Nov 07 2015
parent reply BBaz <bb.temp gmx.com> writes:
On Saturday, 7 November 2015 at 10:15:25 UTC, Alex wrote:
 So the question remains, how to sort? Do you think removing the 
 immutable property from an id is the semantically right way? Or 
 do you have a hint, maybe something like, a dup copy with 
 removing immutability and returning a new, sorted copy? If you 
 think the latter is the way to choose, how is the syntax there? 
 ;)
This fails because in sort() a struct is considered as a value, so the instance are not moved, it looks like this() is called using the instance of another slot. So to get rid of that use some pointer to struct, here when sort() will have to move it'll move the reference: --- import std.stdio; import std.algorithm; struct ku { immutable int id; alias id this; this(int i) { id = i; } int opCmp(ref const ku rhs) const {return id - rhs.id; } } void main() { ku*[] tt = [new ku(2),new ku(1)]; sort(tt); } ---
Nov 07 2015
parent Alex <sascha.orlov gmail.com> writes:
On Saturday, 7 November 2015 at 10:24:03 UTC, BBaz wrote:

 void main()
 {
 	ku*[] tt = [new ku(2),new  ku(1)];
 	sort(tt);
 }
Don't really like this ;) not because writeln(tt); doesn't work any more, but because I have to think about where to use pointers and where not...
Nov 07 2015
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/06/2015 02:54 PM, Alex wrote:
 I'm sure I'm doing a silly mistake somewhere, but why this doesn't work?
 import std.stdio;
 import std.algorithm;

 struct ku
 {
      immutable int id;
      alias id this;

      this(int i)
      {
          id = i;
      }

      int opCmp(ref const ku rhs) const {return id - rhs.id; }
 }

 void main()
 {
      ku[] tt = [ku(2), ku(1)];
      sort(tt);
 }
Continuing from your hint: So, opCmp works but it is sort() that cannot move objects of ku around because of that immutable variable. There may be references to ku objects or its id members and those references may be depending on the immutability of that member. const and immutable members effectively make objects unassignable. (const part is the same in C++.) Ali
Nov 06 2015
parent reply Alex <sascha.orlov gmail.com> writes:
On Saturday, 7 November 2015 at 00:19:56 UTC, Ali Çehreli wrote:

 Continuing from your hint: So, opCmp works but it is sort() 
 that cannot move objects of ku around because of that immutable 
 variable.
So my general question is: why immutable variables shouldn't be able to be moved (inside an array)?
 There may be references to ku objects or its id members and 
 those references may be depending on the immutability of that 
 member. const and immutable members effectively make objects 
 unassignable. (const part is the same in C++.)
And this is also something unexpected: yes, there may be such references and they should stay valid of course. But why shouldn't be a concrete collection of such references be sortable? Why this should affect other references to the individual 'ku' objects?
Nov 07 2015
parent reply Mike Parker <aldacron gmail.com> writes:
On Saturday, 7 November 2015 at 11:48:56 UTC, Alex wrote:

 So my general question is: why immutable variables shouldn't be 
 able to be moved (inside an array)?
To be pedantic, sort isn't actually moving anything. It's reassigning elements, i.e. a[1] = a[2]. The immutable member makes it illegal to assign one instance of ku to another: void main() { ku k = ku(1); k = ku(2); } That's why it's failing. It's actually possible to use move one instance into another, though: void main() { import std.algorithm : move; ku k1 = ku(1); ku k2 = ku(2); k2.move(k1); assert(k1.id == 2); } But sort doesn't work that way. You'll need to take a different approach to sort an array of ku.
Nov 07 2015
next sibling parent reply Alex <sascha.orlov gmail.com> writes:
On Saturday, 7 November 2015 at 14:36:25 UTC, Mike Parker wrote:

 So my general question is: why immutable variables shouldn't 
 be able to be moved (inside an array)?
To be pedantic, sort isn't actually moving anything. It's reassigning elements, i.e. a[1] = a[2]. The immutable member makes it illegal to assign one instance of ku to another: But sort doesn't work that way. You'll need to take a different approach to sort an array of ku.
Yeah... and I'm in the acceptance phase now ;) Do you have a hint, how this approach could be like?
Nov 07 2015
parent reply Alex <sascha.orlov gmail.com> writes:
Found something useful, here:
http://dlang.org/phobos/std_algorithm_sorting.html#makeIndex

with that I can achieve the following
void main(){
	ku[] tt = [ku(2), ku(1)];
	//writeln(tt);
	auto index3 = new size_t[tt.length];
	makeIndex!("a.id < b.id")(tt, index3);
	//writeln(index3);
}

so my index3 contains the right permutation of the tt array.
What I still need is the possibility to take the values of the tt 
array in the order of the generated index. Can somebody give a 
hint how to achieve this?
Nov 07 2015
parent Alex <sascha.orlov gmail.com> writes:
Ok... found the solution. The technical at least.

import std.algorithm;
import std.range;
void main(){
	ku[] tt = [ku(2), ku(1)];
	//writeln(tt);
	auto index3 = new size_t[tt.length];
	makeIndex!("a.id < b.id")(tt, index3);
	auto ind = indexed(tt, index3);
	//writeln(ind);
}

This yield in 'ind' the array of 'tt', ordered in the expected 
way.
So, the remaining open questions are just ideologic now...

Thanks for helping and commenting!
Nov 07 2015
prev sibling parent reply anonymous <anonymous example.com> writes:
On 07.11.2015 15:36, Mike Parker wrote:
 It's actually possible to use move one instance
 into another, though:

 void main() {
      import std.algorithm : move;
      ku k1 = ku(1);
      ku k2 = ku(2);
      k2.move(k1);
      assert(k1.id == 2);
 }
Wat. It even compiles with safe. That's not good.
Nov 07 2015
parent anonymous <anonymous example.com> writes:
On 07.11.2015 16:59, anonymous wrote:
 Wat. It even compiles with  safe. That's not good.
Filed an issue: https://issues.dlang.org/show_bug.cgi?id=15315
Nov 10 2015