www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Comparing two AliasSeq

reply Yuxuan Shui <yshuiv7 gmail.com> writes:
In this example:

     import std.range;
     template expandRange(alias R) if (isInputRange!(typeof(R))) {
         static if (R.empty)
	    alias expandRange = AliasSeq!();
         else
	    alias expandRange = AliasSeq!(R.front(), 
expandRange!(R.drop(1)));
     }

     ///
     unittest {
         import std.range;
         static assert (is(expandRange!(iota(0,5)): 
AliasSeq!(0,1,2,3,4)));
     }

The static assert fails, why?
Mar 24 2017
next sibling parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Sat, Mar 25, 2017 at 03:25:27AM +0000, Yuxuan Shui via Digitalmars-d-learn
wrote:
 In this example:
 
     import std.range;
     template expandRange(alias R) if (isInputRange!(typeof(R))) {
         static if (R.empty)
 	    alias expandRange = AliasSeq!();
         else
 	    alias expandRange = AliasSeq!(R.front(), expandRange!(R.drop(1)));
     }
 
     ///
     unittest {
         import std.range;
         static assert (is(expandRange!(iota(0,5)): AliasSeq!(0,1,2,3,4)));
     }
 
 The static assert fails, why?
Firstly, is(T : U) expects T and U to be types, and expandRange!(...) is not a type (or a list of types), it is a list of values. Second, is(T : U) means "does the type T implicitly convert to the type U?". It checks for implicit convertibility between types, it does not compare values. T -- The right half of the brain controls the left half of the body. This means that only left-handed people are in their right mind. -- Manoj Srivastava
Mar 24 2017
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Saturday, March 25, 2017 03:25:27 Yuxuan Shui via Digitalmars-d-learn 
wrote:
 In this example:

      import std.range;
      template expandRange(alias R) if (isInputRange!(typeof(R))) {
          static if (R.empty)
       alias expandRange = AliasSeq!();
          else
       alias expandRange = AliasSeq!(R.front(),
 expandRange!(R.drop(1)));
      }

      ///
      unittest {
          import std.range;
          static assert (is(expandRange!(iota(0,5)):
 AliasSeq!(0,1,2,3,4)));
      }

 The static assert fails, why?
Well, is expressions normally compare types, not values, and AliasSeq!(0, 1, 2, 3, 4), isn't a type and doesn't contain types. static assert(is(AliasSeq!int == AliasSeq!int)); passes, whereas static assert(is(AliasSeq!0 == AliasSeq!0)); does not. So, I expect that the issue is that you're dealing with values rather than types. You're also using : instead of ==, and : _definitely_ is for types (since it checks for implicit conversion, not equality), so it wouldn't have entirely surprised me if == worked when : didn't, but == doesn't either. What you proobably should do is either convert the AliasSeq's to dynamic arrays or ranges - e.g. [AliasSeq!(0, 1, 2, 3, 4)] or only(AliasSeq!(0, 1, 2, 3, 4)) - though in both cases, that really only makes sense when you already have an AliasSeq, since [] and only will take the values directly. - Jonathan M Davis
Mar 24 2017
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Saturday, 25 March 2017 at 04:23:31 UTC, Jonathan M Davis 
wrote:
 On Saturday, March 25, 2017 03:25:27 Yuxuan Shui via 
 Digitalmars-d-learn wrote:
 In this example:

      import std.range;
      template expandRange(alias R) if 
 (isInputRange!(typeof(R))) {
          static if (R.empty)
       alias expandRange = AliasSeq!();
          else
       alias expandRange = AliasSeq!(R.front(),
 expandRange!(R.drop(1)));
      }

      ///
      unittest {
          import std.range;
          static assert (is(expandRange!(iota(0,5)):
 AliasSeq!(0,1,2,3,4)));
      }

 The static assert fails, why?
Well, is expressions normally compare types, not values, and AliasSeq!(0, 1, 2, 3, 4), isn't a type and doesn't contain types. static assert(is(AliasSeq!int == AliasSeq!int)); passes, whereas static assert(is(AliasSeq!0 == AliasSeq!0)); does not. So, I expect that the issue is that you're dealing with values rather than types. You're also using : instead of ==, and : _definitely_ is for types (since it checks for implicit conversion, not equality), so it wouldn't have entirely surprised me if == worked when : didn't, but == doesn't either. What you proobably should do is either convert the AliasSeq's to dynamic arrays or ranges - e.g. [AliasSeq!(0, 1, 2, 3, 4)] or only(AliasSeq!(0, 1, 2, 3, 4)) - though in both cases, that really only makes sense when you already have an AliasSeq, since [] and only will take the values directly. - Jonathan M Davis
I see. I always thought tuple() is a type... So a tuple of types is a type, but a tuple of mixed types and values is not a type. Doesn't seem very consistent. Here is the solution I will go with: struct test(T...) { } import std.range; static assert (is(test!(expandRange!(iota(0,5))) == test!(0, 1, 2, 3, 4)));
Mar 24 2017
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Saturday, March 25, 2017 04:57:26 Yuxuan Shui via Digitalmars-d-learn 
wrote:
 I see. I always thought tuple() is a type...

 So a tuple of types is a type, but a tuple of mixed types and
 values is not a type. Doesn't seem very consistent.
An AliasSeq isn't really ever a type. AliasSeq!(int, float) is a list of types, not a type itself, and is expressions supports comparing those in at least some instances, because is expressions operate on types, and having them support a list of types is useful. Calling AliasSeq!(int, float) a type would be like claiming that the (int, float) in foo!(int, float) a type. It's a list - a list of template arguments in this case - but it's still a list and not itself a type. An AliaSeq (or tuple as the compiler incorrectly calls it) is essentially a list of symbols or expressions - or aliases - which is why TypeTuple got renamed to AliasSeq; it's not really a tuple (since unlike a tuple, it always expands and is not nestable), and it doesn't hold just types. Also, it's used for template parameters, template arguments, function parameters, and function arguments, so you can't really call it a list of parameters or arguments. So, so it's sort of a list or sequence of aliases, that's what it got changed to - AliasSeq. But that's still not a great name for it. It can just hold too many different things and be used in too many different ways. Essentially though, an AliasSeq is a list of template/function parameters/arguments that happens to be separated from any templates or functions at the moment. In any case, since is expressions are entirely meant for operating on types, having them not work with an AliaSeq that includes values makes sense. In general, mixing types and values in a single AliasSeq isn't a great idea - (though sometimes that's exactly what's required for template arguments). So, code that mixes them is not the norm.
 Here is the solution I will go with:

   struct test(T...) { }
   import std.range;
   static assert (is(test!(expandRange!(iota(0,5))) == test!(0, 1,
 2, 3, 4)));
Why are you using is expressons at all? Why are you creating a type? You're dealing purely with values here. As such, why aren't you just using arrays or ranges? At least with your example here, using an AliasSeq is just complicating life. Dynamic arrays and ranges can be used at compile time via CTFE and are a lot more straightforward to use. - Jonathan M Davis
Mar 24 2017
parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Saturday, 25 March 2017 at 05:20:44 UTC, Jonathan M Davis 
wrote:
 On Saturday, March 25, 2017 04:57:26 Yuxuan Shui via 
 Digitalmars-d-learn wrote:
 [...]
An AliasSeq isn't really ever a type. AliasSeq!(int, float) is a list of types, not a type itself, and is expressions supports comparing those in at least some instances, because is expressions operate on types, and having them support a list of types is useful. Calling AliasSeq!(int, float) a type would be like claiming that the (int, float) in foo!(int, float) a type. It's a list - a list of template arguments in this case - but it's still a list and not itself a type. [...]
Because I want to make use of the "static foreach unrolling" feature (I don't know what's the official name).
 [...]
Mar 24 2017