www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What is the proper way to outline static-if-conditions ?

reply Elmar <chrehme gmx.de> writes:
Hey D people.

Currently in my project I have worked on a unified type interface 
for all arrays which requires fixed-size arrays to be stored as 
pointer (in correspondence to dynamic and associative arrays) and 
allow them being allocated with any selected allocator.

There can be code like this:

```d
enum isPointedStaticArray(T) = (is(T : P*, P) && 
.isStaticArray!P);

//...
static if (.isPointedStaticArray!T)
{
     // ...
}
```

It won't compile when the argument of `isPointedStaticArray()` is 
NO pointer.

The compiler complains, about **`P` being undefined**.

What is the best workaround for this?
It's crazy. I can reverse the problem that it only fails if the 
argument IS a pointer:

```d
	enum isPointedStaticArray(T) =
	(){
		enum condition = `is(`~T.stringof~` : P*, P) && 
.isStaticArray!P`;
		static if (__traits(compiles, mixin(condition)) )
			return mixin(condition);  // "P already defined" error
		else
			return false;
	}();
```

Types defined in `__traits(compiles, ...)` are emitted to the 
outside?!

Okay, this is my current workaround:

```d
enum isPointedStaticArray(T) =
(){
	static if (is(T : P*, P))
		return .isStaticArray!(P);
	else
		return false;
}();

// ...
static if (isPointedStaticArray!T)
{

}
```

for outlining an expression `is(...) && ...`


Is there a simpler way in D to do this? If there only would be a 
`&&&` short circuit operator which doesn't compile the right side 
if the left side wouldn't compile to true.

Did someone already had the idea of a `static-try-catch` which 
catches compilation errors?
Oct 10 2021
next sibling parent Elmar <chrehme gmx.de> writes:
PS: the title is a misnomer. `is(T : P*, P) && isStaticArray!P` 
doesn't either compile when inlined because `P` is not defined 
when not matched.
Oct 10 2021
prev sibling parent reply drug <drug2004 bk.ru> writes:
You just need to check if T is a pointer:
```D
import std;

alias DA = int[];
alias SA = int[3];

alias PSA = SA*;
alias PDA = DA*;

version(all)
	enum isPointedStaticArray(T) = isPointer!T && 
isStaticArray!(PointerTarget!T);
else
	enum isPointedStaticArray(T) = isPointer!T && is(PointerTarget!T : 
P[N], P, size_t N);  // this way you can get array length

static assert(!isPointedStaticArray!DA);
static assert(!isPointedStaticArray!SA);
static assert(!isPointedStaticArray!PDA);
static assert( isPointedStaticArray!PSA);

void main()
{
}
```
https://run.dlang.io/is/qKdx1D

Also you can use another way to detect static array - it can be useful 
if you need to get its length
Oct 10 2021
parent reply Elmar <chrehme gmx.de> writes:
On Sunday, 10 October 2021 at 14:08:13 UTC, drug wrote:
 You just need to check if T is a pointer:
 ```D
 import std;

 alias DA = int[];
 alias SA = int[3];

 alias PSA = SA*;
 alias PDA = DA*;

 version(all)
 	enum isPointedStaticArray(T) = isPointer!T && 
 isStaticArray!(PointerTarget!T);
 else
 	enum isPointedStaticArray(T) = isPointer!T && 
 is(PointerTarget!T : P[N], P, size_t N);  // this way you can 
 get array length

 static assert(!isPointedStaticArray!DA);
 static assert(!isPointedStaticArray!SA);
 static assert(!isPointedStaticArray!PDA);
 static assert( isPointedStaticArray!PSA);

 void main()
 {
 }
 ```
 https://run.dlang.io/is/qKdx1D

 Also you can use another way to detect static array - it can be 
 useful if you need to get its length
Wow, this is a fine solution. I gonna use it, thank you :-) .
Oct 10 2021
parent reply Elmar <chrehme gmx.de> writes:
On Sunday, 10 October 2021 at 14:36:50 UTC, Elmar wrote:
 On Sunday, 10 October 2021 at 14:08:13 UTC, drug wrote:
 You just need to check if T is a pointer:
 ```D
 import std;

 alias DA = int[];
 alias SA = int[3];

 alias PSA = SA*;
 alias PDA = DA*;

 version(all)
 	enum isPointedStaticArray(T) = isPointer!T && 
 isStaticArray!(PointerTarget!T);
 else
 	enum isPointedStaticArray(T) = isPointer!T && 
 is(PointerTarget!T : P[N], P, size_t N);  // this way you can 
 get array length

 static assert(!isPointedStaticArray!DA);
 static assert(!isPointedStaticArray!SA);
 static assert(!isPointedStaticArray!PDA);
 static assert( isPointedStaticArray!PSA);

 void main()
 {
 }
 ```
 https://run.dlang.io/is/qKdx1D

 Also you can use another way to detect static array - it can 
 be useful if you need to get its length
Wow, this is a fine solution. I gonna use it, thank you :-) .
Well, I just wondered why your code would compile and mine wouldn't. The `version(all)` variant will not compile on my computer with `rdmd` because `PointerTarget` only allows pointers. But the 2nd one will compile. The `is()` expression catches the compilation error which is nice. This is sufficient: ```d enum isPointedStaticArray(T) = is(PointerTarget!T : P[N], P, size_t N); ``` It would be nice if one could use pattern-matching for it in D. Is this possible? ```d enum isPointedStaticArray(X : P*, P) = .isStaticArray!(PointerTarget!X); enum isPointedStaticArray(X : else) = false; ```
Oct 10 2021
next sibling parent Elmar <chrehme gmx.de> writes:
On Sunday, 10 October 2021 at 15:01:17 UTC, Elmar wrote:
 ```d
 enum isPointedStaticArray(T) = is(PointerTarget!T : P[N], P, 
 size_t N);
 ```

 ```d
 	enum isPointedStaticArray(X : P*, P) = 
 .isStaticArray!(PointerTarget!X);
 ```
`isStaticArray` is a good example that makes me ask how to outline an `is()` expression without losing the error catching semantics of the inlined `is()` expression.
Oct 10 2021
prev sibling parent reply drug <drug2004 bk.ru> writes:
On 10.10.2021 18:01, Elmar wrote:
 
 Well, I just wondered why your code would compile and mine wouldn't. The 
 `version(all)` variant will not compile on my computer with `rdmd` 
 because `PointerTarget` only allows pointers.
It depends on compiler version. This variant is compiled on version 2.092.1 and above
 
 But the 2nd one will compile. The `is()` expression catches the 
 compilation error which is nice. This is sufficient:
 
 ```d
 enum isPointedStaticArray(T) = is(PointerTarget!T : P[N], P, size_t N);
 ```
 
 It would be nice if one could use pattern-matching for it in D. Is this 
 possible?
 
 ```d
      enum isPointedStaticArray(X : P*, P) = 
 .isStaticArray!(PointerTarget!X);
      enum isPointedStaticArray(X : else) = false;
 ```
 
As I know it's impossible, but you can use a regular template: ```d template isPointedStaticArray(T) { static if (isPointer!T) enum isPointedStaticArray = isStaticArray!(PointerTarget!T); else enum isPointedStaticArray = false; } ``` https://run.dlang.io/is/lR7feP this compiles from 2.086.1 and above
Oct 10 2021
next sibling parent Elmar <chrehme gmx.de> writes:
On Sunday, 10 October 2021 at 15:15:51 UTC, drug wrote:
 As I know it's impossible, but you can use a regular template:
 ```d
 template isPointedStaticArray(T)
 {
     static if (isPointer!T)
         enum isPointedStaticArray = 
 isStaticArray!(PointerTarget!T);
     else
         enum isPointedStaticArray = false;
 }
 ```
 https://run.dlang.io/is/lR7feP
 this compiles from 2.086.1 and above
That's indeed close to pattern matching and is probably the best answer :-) .
Oct 10 2021
prev sibling parent Elmar <chrehme gmx.de> writes:
On Sunday, 10 October 2021 at 15:15:51 UTC, drug wrote:
 It would be nice if one could use pattern-matching for it in 
 D. Is this possible?
 
As I know it's impossible, but you can use a regular template: ...
If anyone is interested in pattern matching, someone provides a package "dpmatch" which uses PEG (some parsing grammer which is implemented in D) to achieve Haskel-style pattern matching, yet for sum-type definitions only. And they use GC + interfaces. Hence it cannot be used with BetterC. Sumtypes can also be created with the `sumtype` package which uses D's delegate literals for pattern matching.
Oct 10 2021