Thread overview
logical operands on strings
Jan 12, 2014
Erik van Velzen
Jan 12, 2014
Meta
Jan 12, 2014
Erik van Velzen
Jan 12, 2014
TheFlyingFiddle
Jan 12, 2014
Meta
Jan 12, 2014
John Colvin
Jan 13, 2014
Mike Parker
Jan 12, 2014
Ali Çehreli
Jan 12, 2014
Meta
Jan 12, 2014
John Colvin
January 12, 2014
I would like to do this:

    string one = x"315c4eeaa8b5f8aaf9174145bf43e1784b";
    string two = x"c29398f5f3251a0d47e503c66e935de81230b59b7a";
    string three = one ^ two;


The closests I've been able to get is:

    string three = xor(one, two);

    string xor(string one, string two) {
        int len = min(one.length, two.length);
        string result;
        for(int i=0; i<len; i++) {
            result ~= one[i] ^ two[i];
        }
        return cast(string)result;
    }

Question 1: is there a more elegant way to implement the function xor? (foreach-ish or std.algorithm)


Then I tried to add operator overloading:

    string opBinary(string op)(string lhs, string rhs) {
        static if( op == "^" )
            return xor(lhs, rhs);
        else static assert(false, "operator not possible");
    }

But it doesn't invoke this function.

Question 2: how would I implement "^" for strings?
January 12, 2014
On Sunday, 12 January 2014 at 18:21:06 UTC, Erik van Velzen wrote:
> I would like to do this:
>
>     string one = x"315c4eeaa8b5f8aaf9174145bf43e1784b";
>     string two = x"c29398f5f3251a0d47e503c66e935de81230b59b7a";
>     string three = one ^ two;
>
>
> The closests I've been able to get is:
>
>     string three = xor(one, two);
>
>     string xor(string one, string two) {
>         int len = min(one.length, two.length);
>         string result;
>         for(int i=0; i<len; i++) {
>             result ~= one[i] ^ two[i];
>         }
>         return cast(string)result;
>     }
>
> Question 1: is there a more elegant way to implement the function xor? (foreach-ish or std.algorithm)
>
>
> Then I tried to add operator overloading:
>
>     string opBinary(string op)(string lhs, string rhs) {
>         static if( op == "^" )
>             return xor(lhs, rhs);
>         else static assert(false, "operator not possible");
>     }
>
> But it doesn't invoke this function.
>
> Question 2: how would I implement "^" for strings?

It looks like your opBinary on strings is an attempt at globally overriding the XOR operator. I'm almost 100% sure this won't work in D. All operator overloads have to be part of a class or struct.
January 12, 2014
On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
>
> It looks like your opBinary on strings is an attempt at globally overriding the XOR operator. I'm almost 100% sure this won't work in D. All operator overloads have to be part of a class or struct.

How would I do that without rewriting an entire string class? It seems I can't even inherit from string.

Forgive me for making the comparison, but I believe in C++ i can simply implement this function and be done with it:

    string operator^(string lhs, string rhs);
January 12, 2014
On Sunday, 12 January 2014 at 18:37:40 UTC, Erik van Velzen wrote:
> On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
>>
>> It looks like your opBinary on strings is an attempt at globally overriding the XOR operator. I'm almost 100% sure this won't work in D. All operator overloads have to be part of a class or struct.
>
> How would I do that without rewriting an entire string class?

Well something like this.

struct MyString
{
   string value;
   alias value this;

   auto opBinary(string op)(string rhs) if( op == "^" )
   {
      string result;
      foreach(i; 0 .. min(value.length, rhs.length))
          result ~= value[i] ^ rhs[i];
      return MyString(result);
   }
}

auto mstr(string s)
{
   return MyString(s);
}

auto s   = "Hello";
auto s2  = "World";


auto res = s.mstr ^ s2;
or
string res = s.mstr ^ s2; //If you want the result to be a string.

While this works it's not that much better then the simple:

auto s = "Hello";
auto s2 = "World";
auto res = s.xor(s2);

> It seems I can't even inherit from string.

In D a string is not a class its just an immutable array (slice) of char.
alias string = immutable(char[]);

January 12, 2014
On Sunday, 12 January 2014 at 18:37:40 UTC, Erik van Velzen wrote:
> On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
>>
>> It looks like your opBinary on strings is an attempt at globally overriding the XOR operator. I'm almost 100% sure this won't work in D. All operator overloads have to be part of a class or struct.
>
> How would I do that without rewriting an entire string class? It seems I can't even inherit from string.
>
> Forgive me for making the comparison, but I believe in C++ i can simply implement this function and be done with it:
>
>     string operator^(string lhs, string rhs);

global operator overloads aren't allowed in D. For your particular problem I would construct a wrapper around string using psuedo-inheritance via 'alias this':

struct MyString
{
    string nativeStr;
    alias nativeStr this;

    auto opBinary(string op)(string rhs)
        if(op == "^")
    {
        return xor(nativeStr, rhs);
    }

    void opOpBinary(string op)(string rhs)
        if(op == "^")
    {
        nativeStr = xor(nativeStr, rhs);
    }
}

All normal string operations on a MyString will be applied to nativeStr thanks to alias this, except the ^ and ^= whch are intercepted by the opBinary and opOpBinary methods in MyString.

The ^= could be more efficient by working in-place.
Also, you should pre-allocate the return string in xor as it's a lot quicker than doing repeated append operations.
January 12, 2014
On 01/12/2014 10:21 AM, Erik van Velzen wrote:
> I would like to do this:
>
>      string one = x"315c4eeaa8b5f8aaf9174145bf43e1784b";
>      string two = x"c29398f5f3251a0d47e503c66e935de81230b59b7a";
>      string three = one ^ two;
>
>
> The closests I've been able to get is:
>
>      string three = xor(one, two);
>
>      string xor(string one, string two) {
>          int len = min(one.length, two.length);
>          string result;
>          for(int i=0; i<len; i++) {
>              result ~= one[i] ^ two[i];
>          }
>          return cast(string)result;
>      }
>
> Question 1: is there a more elegant way to implement the function xor?
> (foreach-ish or std.algorithm)
>
>
> Then I tried to add operator overloading:
>
>      string opBinary(string op)(string lhs, string rhs) {
>          static if( op == "^" )
>              return xor(lhs, rhs);
>          else static assert(false, "operator not possible");
>      }
>
> But it doesn't invoke this function.
>
> Question 2: how would I implement "^" for strings?

XOR is not a valid operation on a UTF-8 code unit. ;) It makes more sense to work with ubyte arrays. However, I found two usability issues with it:

1) std.conv.to did not work from string to ubyte[]; so, I wrote a function.

2) Array-wise operations does not support the following syntax

    auto three = one[] ^ two[];

Otherwise, ^= works with slices:

import std.stdio;

ubyte[] toBytes(string s)
{
    return cast(ubyte[])s.dup;
}

void main()
{
    ubyte[] one = x"55".toBytes;
    ubyte[] two = x"aa".toBytes;

    ubyte[] three = one.dup;
    three[] ^= two[];

    assert(one == x"55");
    assert(two == x"aa");
    assert(three == x"ff");
}

Ali

January 12, 2014
On Sunday, 12 January 2014 at 19:22:57 UTC, Ali Çehreli wrote:
> 2) Array-wise operations does not support the following syntax
>
>     auto three = one[] ^ two[];

Is this a bug or intended?
January 12, 2014
On Sunday, 12 January 2014 at 19:12:13 UTC, TheFlyingFiddle wrote:
> On Sunday, 12 January 2014 at 18:37:40 UTC, Erik van Velzen wrote:
>> On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
>>>
>>> It looks like your opBinary on strings is an attempt at globally overriding the XOR operator. I'm almost 100% sure this won't work in D. All operator overloads have to be part of a class or struct.
>>
>> How would I do that without rewriting an entire string class?
>
> Well something like this.
>
> struct MyString
> {
>    string value;
>    alias value this;
>
>    auto opBinary(string op)(string rhs) if( op == "^" )
>    {
>       string result;
>       foreach(i; 0 .. min(value.length, rhs.length))
>           result ~= value[i] ^ rhs[i];
>       return MyString(result);
>    }
> }
>
> auto mstr(string s)
> {
>    return MyString(s);
> }
>
> auto s   = "Hello";
> auto s2  = "World";
>
>
> auto res = s.mstr ^ s2;
> or
> string res = s.mstr ^ s2; //If you want the result to be a string.
>
> While this works it's not that much better then the simple:
>
> auto s = "Hello";
> auto s2 = "World";
> auto res = s.xor(s2);
>
>> It seems I can't even inherit from string.
>
> In D a string is not a class its just an immutable array (slice) of char.
> alias string = immutable(char[]);

You can also use opBinaryRight for when your custom string class is on the right side of the operand, so string ^ MyString also works. This pretty much obviates the need for global operator overloading, at least in this case.
January 12, 2014
On Sunday, 12 January 2014 at 19:27:18 UTC, Meta wrote:
> On Sunday, 12 January 2014 at 19:22:57 UTC, Ali Çehreli wrote:
>> 2) Array-wise operations does not support the following syntax
>>
>>    auto three = one[] ^ two[];
>
> Is this a bug or intended?

intended. It would require an implicit allocation, which is incongruent with array operations being fast. It's been discussed at length.
January 13, 2014
On 1/13/2014 3:37 AM, Erik van Velzen wrote:
> On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
>>
>> It looks like your opBinary on strings is an attempt at globally
>> overriding the XOR operator. I'm almost 100% sure this won't work in
>> D. All operator overloads have to be part of a class or struct.
>
> How would I do that without rewriting an entire string class? It seems I
> can't even inherit from string.

In D, string is not a class. It's an alias for an immutable array of char.