Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Ticket #1259 (closed defect: fixed)

Opened 16 years ago

Last modified 16 years ago

Variant[] elements are sorted in desc order

Reported by: tsalm Assigned to: sean
Priority: major Milestone:
Component: Core Functionality Version: 0.97 RC1
Keywords: triage Cc:

Description (Last modified by fawzi)

In this example, int elements are puts in a Variant array. And this array is sorted and after this, displays, but in a desc order.

import tango.io.Stdout;
import tango.core.Variant;
 
void testSortVariant()
{
 // Create an array of int store in Variant
 Variant[] variants;
 foreach(v;[4,1,8,100,99])
 {
   variants ~= Variant(v);
 }
 
 // Sort the variant array
 variants.sort;
 
 // Print values
 foreach(v;variants)
 {
  Stdout( v.get!(int) ).newline;
 }
 
}
 
 
void main()
{
 testSortVariant;
}

Change History

08/22/08 00:23:58 changed by fawzi

I removed my previous comment because I saw an error, and correcting it I found the real problem. sort does not really use opCmp or <, but some other comparison. Why? I gave a quick look at the code, and I did not understand why, it is late, and I leave this to someone else. Anyway here is some code that shows the problem

import tango.io.Stdout;
import tango.core.Variant;


class A{
 int i;
 this(int j){ i=j; }
 int opCmp(A b) { return (i-b.i); }
}

class B{ // opposite ordering
 int i;
 this(int j){ i=j; }
 int opCmp(B b) { return -(i-b.i); }
}

void main()
{
 int a=1,b=2;
 TypeInfo t= typeid(int);
 Stdout("typeinfo")(t.compare(&a,&b))(" ")(a<b).newline;
 auto aa1=[a,b];

 A a2=new A(a),b2=new A(b);
 Stdout("A")(a2.opCmp(b2))(" ")(a2<b2).newline;
 auto aa2=[a2,b2];

 B a3=new B(a),b3=new B(b);
 Stdout("B")(a3.opCmp(b3))(" ")(a3<b3).newline;
 auto aa3=[a3,b3];

 Variant v1=Variant(a);
 Variant v2=Variant(b);
 Stdout("Variant")(v1.opCmp(v2))(" ")(v1<v2).newline;
 auto aa4=[v1,v2];

 aa1.sort;
 aa2.sort;
 aa3.sort;
 aa4.sort;

 foreach(v;aa1) Stdout( v )(" ");
 Stdout.newline;
 foreach(v;aa2) Stdout( v.i )(" ");
 Stdout.newline;
 foreach(v;aa3) Stdout( v.i )(" ");
 Stdout.newline;
 foreach(v;aa4) Stdout( v.get!(int) )(" ");
 Stdout.newline;
}

as it outputs

typeinfo-1 true
A-1 true
B1 false
Variant-1 true
1 2 
2 1 
2 1 
2 1 

08/22/08 09:01:52 changed by tsalm

Its' because opCmp need an object as argument.

In this example, this work :

class A{
 int i;
 this(int j){ i=j; }
 int opCmp(Object ob) {A b = cast(A)ob; return (i-b.i); }
}

class B{ // opposite ordering
 int i;
 this(int j){ i=j; }
 int opCmp(Object ob) {B b = cast(B)ob; return -(i-b.i); }
}

But dmd don't want to cast Object to Variant, which is a struct :-(

08/22/08 09:13:00 changed by tsalm

well, for struct only, the syntax is correct, don't understand why it don't work :

struct X
{
 int opEquals(T)(T t)
 {
  Stdout("compare by T").newline;
  return 0;
 }

 int opCmp(T)(T t)
 {
  Stdout("> by T").newline;
  return -1;
 }
}

void main()
{
  X x;
  if (x<5)
    Stdout("Yes!").newline;
  else
    Stdout("NO!").newline;
}

08/22/08 11:28:58 changed by tsalm

Found the problem : http://www.digitalmars.com/d/1.0/arrays.html chapter "Using Structs or Unions as the KeyType?".

If we want a struct correctly sorted, opCmp must take exactly the type of the struct :

import tango.io.Stdout;

struct X
{
 int val;

 int opEquals(X t)
 {
  Stdout("compare by X ?").newline;
  return val == t.val;
 }

 int opCmp(X x)
 {
  Stdout("< > by X ?").newline;
  return val - x.val;
 }
}

void main()
{
  X a,b,c,d;

  a.val = 5;
  b.val = 2;
  c.val = 98;
  d.val = -12;

  X[] array = [a,b,c,d];
  array.sort;
  foreach(X x;array)
  {
    Stdout(x.val).newline;
  }
}

08/22/08 13:00:19 changed by fawzi

  • description changed.

Well you are right tsalm, the array own sort is very picky about the opCmp he wants. If one uses tango.core.Array it works correctly in all the previous cases, but as the array already has a sort method external sorts are used only when the internal sort does not match (for example when you pass a predicate to it). You still use tango version by calling it like this:

   import tango.core.Array;
...
   sort(array);
  // array.sort does not call tango version

and obviously you can always use the predicate version

   import tango.core.Array;
...
   sort(array,(int x,int x){return x<y;});
// or
   array.sort((int x,int x){return x<y;});

08/22/08 13:03:59 changed by fawzi

  • description changed.

ehm this was meant to go in my comment:

maybe one should write something about it in the documentation...

08/22/08 20:25:44 changed by tsalm

09/08/08 20:25:50 changed by sean

  • status changed from new to closed.
  • resolution set to fixed.

This was fixed by a change to the runtime code a week or so ago. I'm marking this ticket closed.