May 12, 2022

On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:

>

[snip]

is ( Type : TypeSpecialization , TemplateParameterList )
is ( Type == TypeSpecialization , TemplateParameterList )
is ( Type Identifier : TypeSpecialization , TemplateParameterList )
is ( Type Identifier == TypeSpecialization , TemplateParameterList )

I never remember those variants, because basically you never need them...
They were required for std.traits and that's it.

What's the difference between a Type and Type Identifier?

May 12, 2022

On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote:

>

On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:

>

[snip]

is ( Type : TypeSpecialization , TemplateParameterList )
is ( Type == TypeSpecialization , TemplateParameterList )
is ( Type Identifier : TypeSpecialization , TemplateParameterList )
is ( Type Identifier == TypeSpecialization , TemplateParameterList )

I never remember those variants, because basically you never need them...
They were required for std.traits and that's it.

What's the difference between a Type and Type Identifier?

int, char and friends are Type

In int a, string c, a and c are Identifiers

May 12, 2022

On 5/12/22 11:18 AM, jmh530 wrote:

>

On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:

>

[snip]

is ( Type : TypeSpecialization , TemplateParameterList )
is ( Type == TypeSpecialization , TemplateParameterList )
is ( Type Identifier : TypeSpecialization , TemplateParameterList )
is ( Type Identifier == TypeSpecialization , TemplateParameterList )

I never remember those variants, because basically you never need them...
They were required for std.traits and that's it.

What's the difference between a Type and Type Identifier?

Type is a type, Identifier is an identifier.

In general, after such expressions, Identifier is now declared as an alias to the type, if the is expression was true. But in special forms, it might be a portion of the type.

So e.g.:

static if(is(Foo Bar == struct))
{
  // inside here, it was determined that `Foo` was a type, and it is a
  // struct, and now, `Bar` is aliased to `Foo`
}

It's very confusing syntax though.

-Steve

May 12, 2022
On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote:
> What's the difference between a Type and Type Identifier?

The is expression roughly follows variable declaration style.

You write

int a;

to declare a new symbol named `a` of type `int`.

Similarly,

static if(is(T a))

declares a new symbol of type `a` if `T` is a valid type. (Of course, in this case, a and T are aliases of each other, so it isn't super useful, but in the more complex matches using the == and : operators, it might be different.)

The Identifier is optional.
May 12, 2022

On Thursday, 12 May 2022 at 15:31:03 UTC, Steven Schveighoffer wrote:

>

On 5/12/22 11:18 AM, jmh530 wrote:

>

On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:

>

[snip]

is ( Type : TypeSpecialization , TemplateParameterList )
is ( Type == TypeSpecialization , TemplateParameterList )
is ( Type Identifier : TypeSpecialization , TemplateParameterList )
is ( Type Identifier == TypeSpecialization , TemplateParameterList )

I never remember those variants, because basically you never need them...
They were required for std.traits and that's it.

What's the difference between a Type and Type Identifier?

Type is a type, Identifier is an identifier.

In general, after such expressions, Identifier is now declared as an alias to the type, if the is expression was true. But in special forms, it might be a portion of the type.

So e.g.:

static if(is(Foo Bar == struct))
{
  // inside here, it was determined that `Foo` was a type, and it is a
  // struct, and now, `Bar` is aliased to `Foo`
}

It's very confusing syntax though.

-Steve

yess that kind of stuff

May 12, 2022
On Thursday, 12 May 2022 at 15:32:24 UTC, Adam D Ruppe wrote:
> On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote:
>> What's the difference between a Type and Type Identifier?
>
> The is expression roughly follows variable declaration style.
>
> You write
>
> int a;
>
> to declare a new symbol named `a` of type `int`.
>
> Similarly,
>
> static if(is(T a))
>
> declares a new symbol of type `a` if `T` is a valid type. (Of course, in this case, a and T are aliases of each other, so it isn't super useful, but in the more complex matches using the == and : operators, it might be different.)
>
> The Identifier is optional.

Ah, yeah I know about that.
May 12, 2022
On 5/11/22 18:06, Christopher Katko wrote:

> Cool useful library functions like sumElement that magically don't work
> on static arrays.

Yeah, that sometimes gets me as well. Although it is trivial to deal with, the programmer may be surprised by the strange error messages:

  int[3] arr = [ 1, 2, 3 ];
  assert(sum(arr) == 6);

Error: template `std.algorithm.iteration.sum` cannot deduce function from argument types `!()(int[3])`
/usr/include/dlang/dmd/std/algorithm/iteration.d(7234): Candidates are: `sum(R)(R r)`
  with `R = int[3]`
  must satisfy the following constraint:
`       isInputRange!R`

WHAT? :) But the clue is on the last line above.

For completeness and for people who may not know the reason, D's static arrays and dynamic arrays are different in a number of ways but what matters here is that static arrays are not ranges because they cannot shrink. (Arguably, static arrays could be RandomAccessRanges but D's range hierarchy does not allow RandomAccessRanges that are not also InputRanges and ForwardRanges.)

So, the commented-out assert below cannot be compiled but the two following lines do compile by simply adding the two characters [] to get a range to all elements:

import std.algorithm;

void main() {
  int[3] arr = [ 1, 2, 3 ];
  // assert(sum(arr) == 6);
  assert(sum(arr[]) == 6);
  assert(arr[].sum == 6);
}

> 'private' is per module, not per class, making it pretty much useless
> for preventing incorrect access and using .

My view on private has changed over the years. I need to be convinced that there is usage that needs to be protected. :) I don't see people using types freely especially the ones that are in the same module. The only argument for private is to allow changing the implementation of published libraries in the future.

Still, private could have been a convention like naming variables with an underscore (which Go chose) and it could have been as effective. People who went around the convention and accessed the private members would either be happy or deserved what they got. I really don't see any problem on this matter for a programming language to go out of their way to protect people from themselves.

I started wondering as I wrote those: Perhaps IDEs make this a bigger issue? If they do respect private/public, perhaps they include member names in menus to pick from and the programmer does not want to see the private members there?

> I just realized foreach copies by value by default. Maybe. Sometimes.
> When?

It is always by-value when passing parameters and in foreach (which can be defined by opApply) and everywhere else. As Steve said, the confusion is when the copied thing is a reference itself. You end up getting another reference to data.

Ali

May 12, 2022
On 5/11/22 19:35, zjh wrote:
> On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote:
>> What are you stuck at? What was the most difficult features to
>> understand? etc.
>>
>
> I don't know the progress of `interface to C++`.
> I want to use my C++ functions in `d`.

That direction is easier:


https://dlang.org/spec/cpp_interface.html#calling_global_d_functions_from_cpp

(Also see "Using D Classes From C++" on the same page.)

The problem is calling into C++ where C++ templates are involved. As D does not include a C++ compiler, it cannot instantiate C++ templates automatically. (The programmer must instantiate explicitly as needed on the C++ side.)

Ali

May 12, 2022
On 5/12/22 07:28, Guillaume Piolat wrote:
> On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote:
>> - Certain variant forms of the `is` Expression are not obvious (not
>> intuitive), I'm pretty sure I still cant use them without a quick look
>> to the specs.
>
> That one was a trouble to hear about =>
> http://p0nce.github.io/d-idioms/#Get-parent-class-of-a-class-at-compile-time

Cool trick but "parent" confused me there. I think you mean "base". :)

It looks like there is an alternative now:

  https://dlang.org/phobos/std_traits.html#BaseTypeTuple

Ali

May 12, 2022
On Thu, May 12, 2022 at 12:13:32PM +0000, Basile B. via Digitalmars-d-learn wrote: [...]
> Problem is more (from https://dlang.org/spec/expression.html#is_expression)
> 
> ```
> is ( Type : TypeSpecialization , TemplateParameterList )
> is ( Type == TypeSpecialization , TemplateParameterList )
> is ( Type Identifier : TypeSpecialization , TemplateParameterList )
> is ( Type Identifier == TypeSpecialization , TemplateParameterList )
> ```
> 
> I never remember those variants, because basically you never need them...  They were required for std.traits and that's it.

Not true. I use these all the time in generic code. Basically, they allow you to do IFTI-like template pattern-matching using static-if's. This is eminently useful for inspecting incoming types in template functions. For example, in serialization code, I would do something like:

	auto serialize(T)(T data) {
		static if (is(T == string))
		{
			... // straightforward string encoding
		}
		else static if (is(T : U[], U))
			// this means: "T matches the pattern `U[]`,
			// where U is some arbitrary type"
		{
			... // non-string array encoding
			// note that in this block, `U` is defined to be
			// the array element; very convenient for
			// further type dissection
		}
		else static if (is(T : U[V], U, V))
			// this means: "T matches the pattern `U[V]`,
			// where U and V are arbitrary types"
		{
			... // AA encoding
			// similarly, in this block U is the value type
			// and V is the key type, very convenient for
			// further type dissection
		}
		else static if (is(T : MyType!(U), string U))
			// this means: "T matches the pattern
			// `MyType!(U)` where U is some string"
		{
			... // special handling for instantiations of
			    // MyType with string argument
			// in this block, U == string
		}
		... // and so on
	}

I concede that the documentation isn't exactly easy to understand on a first read; it took me many tries before it "clicked".  But once you understand the general pattern, most of the cases make sense and is pretty predictable.

There *are* one or two special cases, granted, but those are exceptional and there are already std.traits wrappers that expose a friendlier API. The worst offender in this category is __parameters, about which I wrote years ago here:

	https://forum.dlang.org/thread/vpjpqfiqxkmeavtxhyla@forum.dlang.org

Still, putting this ugly special case aside, the rest of is(...) syntax mostly conforms to the above pattern, and is readily understandable once you learn the pattern.


T

-- 
Written on the window of a clothing store: No shirt, no shoes, no service.