Re: Why not allow elementwise operations on tuples?

2023-01-19 Thread Sergei Nosov via Digitalmars-d-learn

On Wednesday, 18 January 2023 at 16:42:00 UTC, JG wrote:
I guess such a method wouldn't be particularly generic since a 
tuple does not need to consist of types that have the same 
operations e.g. Tuple!(int,string) etc


That's where `areCompatibleTuples` function comes in!


Re: Why not allow elementwise operations on tuples?

2023-01-16 Thread Sergei Nosov via Digitalmars-d-learn

On Friday, 13 January 2023 at 15:27:26 UTC, H. S. Teoh wrote:
On Fri, Jan 13, 2023 at 02:22:34PM +, Sergei Nosov via 
Digitalmars-d-learn wrote:

Hey, everyone!

I was wondering if there's a strong reason behind not 
implementing elementwise operations on tuples?


Say, I've decided to store 2d points in a `Tuple!(int, int)`. 
It would
be convenient to just write `a + b` to yield another 
`Tuple!(int,

int)`.


I've written a Vec type that implements precisely this, using 
tuples behind the scenes as the implementation, and operator 
overloading to allow nice syntax for vector arithmetic.


Yeah, that's clear that such an implementation is rather 
straightforward. Although, I'm a bit confused with your 
implementation - 1. it doesn't seem to use tuples behind the 
scenes despite your claim (it uses static array) 2. `alias impl 
this;` introduces some unexpected interactions (e.g. `~` and 
`toString` are "intercepted" by the array implementation and 
yield "wrong" results).


Anyway, my original question was primarily about reasoning - why 
there's no implementation specifically for `std.Tuple`? If it's a 
"feature, not a bug" - what's the best way to provide an 
implementation on the client side?


Why not allow elementwise operations on tuples?

2023-01-13 Thread Sergei Nosov via Digitalmars-d-learn

Hey, everyone!

I was wondering if there's a strong reason behind not 
implementing elementwise operations on tuples?


Say, I've decided to store 2d points in a `Tuple!(int, int)`. It 
would be convenient to just write `a + b` to yield another 
`Tuple!(int, int)`.


I can resort to using `int []` arrays and write elementwise 
operations as `c[] = a[] + b[]` which is almost fine - but it 
uses dynamic allocation and forces the user to create an explicit 
destination variable.


It seems a bit awkward given that it's fairly straightforward to 
write smth as


```
T opBinary(string op, T)(T lhs, T rhs)
if (isTuple!T)
{
T result;

static foreach (i; 0 .. T.Types.length)
{
mixin("result.field[i] = 
lhs.field[i]"~op~"rhs.field[i];");

}

return result;
}
```

You only need to turn it into a member function to make it work. 
You can even make it more general and allow such operations for 
different, but compatible tuple types (there's a function 
`areCompatibleTuples` to check for such compatibility). Yet, 
there's only a specialization for tuple concatenation of 
`opBinary` (and an implementation of `opCmp` and `opAssign`).


So, to repeat the question - is this a deliberate decision to not 
implement the default elementwise operation?




Re: Can you simplify nested Indexed types?

2022-12-27 Thread Sergei Nosov via Digitalmars-d-learn

On Tuesday, 27 December 2022 at 16:43:49 UTC, Ali Çehreli wrote:

On 12/27/22 07:09, Sergei Nosov wrote:
If what you are looking for is a way of defining a variable for 
"any InputRange that produces a specific type (size_t in this 
case)", then there is inputRangeObject, which uses OOP:


  https://dlang.org/phobos/std_range_interfaces.html#InputRange

I have an additional example here:


http://ddili.org/ders/d.en/ranges_more.html#ix_ranges_more.inputRangeObject

Ali


Thanks, everyone!

I guess, this answer is the closest to what I was looking for. 
Somehow, I missed the range interfaces (and was considering to 
use `Variant` or smth). It does seem to answer the original 
question, albeit with layer(s) of indirection.


```
  auto indicies = iota(3);
  RandomAccessFinite!int ai = indexed(a, 
indicies).inputRangeObject;

  ai = indexed(ai, iota(2)).inputRangeObject;
```

Still, my gut feel is that some compile-time solution is possible 
- will, probably, tinker with it for a little more.


Why not use filter(), isn't it important to filter out what's 
in range?


That does something different.

Well, pretty sure this isn't what you meant by "same variable" 
but since it technically does what you want, I decided to share 
it: Basically I'm abusing array and this thing might be pretty 
memory heavy...


Yeah, using arrays is another alternative, but as you mention, it 
uses more memory and makes index evaluation eager (vs lazy).





Re: Can you simplify nested Indexed types?

2022-12-27 Thread Sergei Nosov via Digitalmars-d-learn

On Tuesday, 27 December 2022 at 15:20:24 UTC, Salih Dincer wrote:
On Tuesday, 27 December 2022 at 15:09:11 UTC, Sergei Nosov 
wrote:

Consider, I have the following code:

```d
auto a = [3, 6, 2, 1, 5, 4, 0];

auto indicies = iota(3);
auto ai = indexed(a, indicies);
//ai = indexed(ai, iota(2));

writeln(ai);
```


I confuse about comment line that I mark...

SDB@79


Not sure I'll be more helpful, but I'll try to add more details.

I have an array and I use `indexed` on it. Conceptually, I now 
have a second array, but it doesn't exist in memory explicitly - 
only a function to map indicies from "second array" to "first 
array" is stored; all the values are stored once - in the "first 
array".


Now, I want to have third array that will do the same trick with 
the second array. The problem is that the second array is not 
really an array (but, conceptually, it is an array with random 
access). If I create a new variable with `auto` as type - 
obviously, it works. But can I use the same variable I used to 
store the "second array"? (In the provided code that doesn't work 
because of the type mismatch).


Re: Function to print a diamond shape

2014-03-21 Thread Sergei Nosov

On Thursday, 20 March 2014 at 21:25:03 UTC, Ali Çehreli wrote:
This is a somewhat common little exercise: Write a function 
that takes the size of a diamond and produces a diamond of that 
size.


When printed, here is the output for size 11:

 *
***
   *
  ***
 *
***
 *
  ***
   *
***
 *

What interesting, boring, efficient, slow, etc. ways are there?

Ali


Probably, the most boring way is

foreach(i; 0..N)
{
foreach(j; 0..N)
write( *[i + j = N/2  i + j  3*N/2  i - j = N/2 
 j - i = N/2]);

writeln;
}


Re: Function to print a diamond shape

2014-03-21 Thread Sergei Nosov
On Friday, 21 March 2014 at 13:59:27 UTC, Vladimir Panteleev 
wrote:

On Friday, 21 March 2014 at 12:32:58 UTC, Sergei Nosov wrote:

On Thursday, 20 March 2014 at 21:25:03 UTC, Ali Çehreli wrote:
This is a somewhat common little exercise: Write a function 
that takes the size of a diamond and produces a diamond of 
that size.


When printed, here is the output for size 11:

   *
  ***
 *
***
*
***
*
***
 *
  ***
   *

What interesting, boring, efficient, slow, etc. ways are 
there?


Ali


Probably, the most boring way is

foreach(i; 0..N)
{
   foreach(j; 0..N)
   write( *[i + j = N/2  i + j  3*N/2  i - j = 
N/2  j - i = N/2]);


write( *[abs(i-N/2) + abs(j-N/2) = N/2]);


   writeln;
}


Beat me. Yours is even more boring. =)


Just-run-the-unittests

2014-03-16 Thread Sergei Nosov

Hi!

Suppose I have a small .d script that has a main. Is there any 
simple way to just run the unit tests without running main at all?


I thought -main switch was intended for this, but apparently it 
works only if there's no main defined at all, otherwise, it 
issues a double main definition error.


I could place main into a separate module but its really awkward 
to create 2 files for a small script.


Re: Just-run-the-unittests

2014-03-16 Thread Sergei Nosov

On Sunday, 16 March 2014 at 08:22:04 UTC, safety0ff wrote:

On Sunday, 16 March 2014 at 07:59:33 UTC, Sergei Nosov wrote:

Hi!

Suppose I have a small .d script that has a main. Is there any 
simple way to just run the unit tests without running main at 
all?


Here's the first thing that came to mind:
If you never want to both unit tests and regular main:
 code begins 
import std.stdio;
version(unittest) void main(){}
else
void main() { writeln(Hello world!); }

unittest { writeln(Hello unit testing world!); }
 code ends 

If you sometimes want to have your normal main with unit 
testing you can replace version(unittest) with 
version(nopmain) or some other custom version identifier and 
compile with -version=nopmain when you want the dummy main.


Thx! That's better, but I think -main switch could be made to 
work like 'add or replace main by stub' instead of just 'add'. I 
don't think it'll hurt anybody, what do you think?


Re: foreach/iota countdown

2014-02-18 Thread Sergei Nosov

On Tuesday, 18 February 2014 at 05:21:24 UTC, Brian Schott wrote:

On Monday, 17 February 2014 at 19:22:38 UTC, simendsjo wrote:

Should the following two uses be a compile-time error?
 foreach(i; 10 .. 0) // Never executes

 foreach(i; iota(10, 0)) // .. neither does this

I would like the second to either be a compile-time error or 
automagically use a negative step.


So we need to use a negative step in iota() or use a for loop
 foreach(i; iota(10, 0, -1)) // as expected


I just added this check to DScanner:

-
import std.stdio;

void main(string[] args)
{
auto x = args[3 .. 2];
foreach (i; 20 .. 10)
{
}
}
-
/home/alaran/tmp/test.d(5:16)[warn]: 3 is larger than 2. This 
slice is likely incorrect.
/home/alaran/tmp/test.d(6:22)[warn]: 20 is larger than 10. Did 
you mean to use 'foreach_reverse( ... ; 10 .. 20)'?


Isn't foreach_reverse being deprecated?


Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Sergei Nosov

On Wednesday, 29 January 2014 at 13:15:30 UTC, Cooler wrote:
On Wednesday, 29 January 2014 at 12:40:00 UTC, Tobias Pankrath 
wrote:

On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:
Thank you for detailed explanation. But the question is - Is 
that correct that language allows ambiguous behavior?


Where is it ambiguous?


Ambiguity is here...
When I call fun1() or fun2() I know the behavior directly from 
function signature (read the comments in my first post). For 
fun3() case the caller side don't know the behavior directly 
from function signature. To know what will happen with array 
a, the caller must see to fun3() body.
Ambiguity is - in first and second cases the caller knows what 
happens with a, but in third case the caller does not know 
what happens with a.


I believe you encounter an array reallocation.

If fun3 doesn't change the size of the array - you will see every 
change made by fun3 to the contents of `a` (but the `a` itself 
cannot be changed - only the contents). No other way around.


If, however, in fun3 you change the size of the array - it may 
reallocate. Like, if you're appending to `x` - it will allocate a 
new array and make x point to it. Now `a` and `x` point to 
distinct arrays. And any change you do using `x` won't be seen by 
`a`. And, yes, this is the intended behavior.




Re: Array as an argument, ambiguous behaviour.

2014-01-29 Thread Sergei Nosov

On Wednesday, 29 January 2014 at 15:11:33 UTC, Cooler wrote:
Yes, that is how slices work in D. The following article 
explains the non-determinism that you mention:


 http://dlang.org/d-array-article.html

Ali


Thank you for the article.
Quotation from the article It is a good idea to note in the 
documentation how the passed in slice might or might not be 
overwritten.
May be just prohibit at language level the case of fun3() 
function, to do not allow unpredictable behavior?


This behavior is just a consequence of the deliberate decision on 
how arrays should be implemented.


Any decision would be a trade-off. Like, if you just disallow 
this signature, you will have to use .dup at the caller side if 
you want the semantics of fun3. And often this copy might be 
unnecessary.


It's really like a ball under the carpet. You make it flat in one 
place, but the ball pops up in the other.


The trade-off that D chooses is pretty reasonable. You just have 
to accept that and get used to it.


Re: enum value vs. immutable

2013-12-01 Thread Sergei Nosov

On Monday, 2 December 2013 at 07:31:56 UTC, Sergei Nosov wrote:

On Monday, 2 December 2013 at 05:57:33 UTC, CJS wrote:
I was reading the enum page of Ali Çehreli's (excellent) D 
book (http://ddili.org/ders/d.en/enum.html), and I'm confused 
by an enum value (not enum type), such as

  enum secondsPerDay = 60 * 60 * 24;
In that situation I would have used an immutable variable. Is 
there any reason to prefer enum vs. immutable when defining 
constants?


enum is a compile-time constant and an immutable variable is 
not.


As an example, in order to create a enum variable you have to 
know it's value at compile time, e.g. you can't read it from 
file. On the contrary, you can read a string from file and 
string is the same thing as immutable(char) in D.


Typo - the string is the same thing as immutable(char)[] in D 
(note the rectangular braces)


Re: enum value vs. immutable

2013-12-01 Thread Sergei Nosov

On Monday, 2 December 2013 at 05:57:33 UTC, CJS wrote:
I was reading the enum page of Ali Çehreli's (excellent) D book 
(http://ddili.org/ders/d.en/enum.html), and I'm confused by an 
enum value (not enum type), such as

   enum secondsPerDay = 60 * 60 * 24;
In that situation I would have used an immutable variable. Is 
there any reason to prefer enum vs. immutable when defining 
constants?


enum is a compile-time constant and an immutable variable is not.

As an example, in order to create a enum variable you have to 
know it's value at compile time, e.g. you can't read it from 
file. On the contrary, you can read a string from file and string 
is the same thing as immutable(char) in D.


Re: Function literal bug?

2013-11-28 Thread Sergei Nosov

On Thursday, 28 November 2013 at 08:23:22 UTC, bearophile wrote:

Global structs don't need the static attribute.


I've thought so, but added it just as a I really mean, that I 
don't need context.


This version of your code gives the output 6 6 on Windows 32 
bit:


Do you have a 64-bit OS at hand?


I don't know why in A2 it infers a delegate.


There's at least 2 of us.




Re: Function literal bug?

2013-11-28 Thread Sergei Nosov

On Thursday, 28 November 2013 at 10:23:39 UTC, Kenji Hara wrote:

It's a known front-end issue.

https://d.puremagic.com/issues/show_bug.cgi?id=11545

Kenji Hara


Great! Does this pull resolve both issues? (correct length and 
x=x syntax)


Function literal bug?

2013-11-27 Thread Sergei Nosov

Hi!

This is kind of bug report/question.

I'm running Ubuntu 12.04 (x64), DMD v2.064.2 and have the 
following code:


T identity(T)(T e) { return e; }
struct S(alias Func)
{
void call()
{
import std.stdio;
writeln(Func(string).length);
}
}
static struct S1
{
alias S!(identity) A1;
//alias S!(x = x) A2;
alias S!(function string (string e) { return e; }) A3;
}
void main()
{
S1.A1.init.call();
S1.A3.init.call();
}

The main complaint is that function literal is somehow broken in 
that case. The output of the program is

6
4527264
For some reason, length in the second case is wrong.

Another question (which I believe is reasonable) is that I cannot 
use the (x = x) syntax for function literal (the commented alias 
A2). The compilation error is:


tmp.d(15): Error: delegate tmp.S1.__lambda4!string.__lambda4 
function literals cannot be class members
tmp.d(8): Error: template instance tmp.S1.__lambda4!string error 
instantiating

tmp.d(15):instantiated from here: S!((x) = x)
tmp.d(8): Error: this for __lambda4 needs to be type S1 not type 
S!((x) = x)


I assume, compiler infers the type of the literal to be delegate, 
but it's clearly not the case, since I don't need no context here.


I appreciate any comments.


Re: What does it mean void[]?

2013-11-15 Thread Sergei Nosov

On Friday, 15 November 2013 at 09:19:04 UTC, Orfeo wrote:
I have found in the module 
https://github.com/NCrashed/serial-port/blob/master/source/serial/device.d

this function:

 void write(const(void[]) arr) {
...

What exactly is void[]? An array of pointers? An array of 
anything?


Thank you


It's semantics is an array of octets. Similar, to void * in 
C++, except, the overall length in bytes is known.


alias template parameter

2013-06-21 Thread Sergei Nosov

Hi!

I've been thinking about how alias template parameters work and 
I'm really confused =)


It makes perfect sense for literals, names, etc. But what I can't 
get is how does it work for delegates.


If I have a function
auto apply(alias fun, T...)(T args)
{
return fun(args);
}

And then I have
int y = 2;
apply!(x = y)(1);

How in the world does this work? Is the context address known at 
compile-time?


shared vs __gshared

2013-06-10 Thread Sergei Nosov

Hi!

I'm puzzled with what's the difference between shared and 
__gshared. Until now I've (mistakenly) considered that shared 
variables are free from low-level data races. I.e. the operations 
with shared data are atomic. And that __gshared is the usual 
(in C++ sense) shared data.


So, in my understanding, it was that if I do

shared int s = 0;
void inc()
{
s++;
}
void main()
{
foreach (i; iota(100_000).parallel)
s++;
}

I will always get s == 100_000 by the end of foreach loop. And if 
I use __gshared specifier, I will get the undefined value less or 
equal 100_000.


But now I've run the test and I get the undefined value result 
for both shared and __gshared.


I've looked this up in TDPL, and careful reading got me that 
shared guarantees only that the result of a write is instantly 
visible to all threads. So according to this, I can load the 
value in register, change it there, wait until someone else 
rewrites the value, and put my version on top, discarding someone 
else's result.


Is this how shared is supposed to work? If so, how is the 
__gshared different from it? Does it not guarantee that the 
result of a write is instantly visible to all threads? If so, 
does this difference really matter?


Re: shared vs __gshared

2013-06-10 Thread Sergei Nosov

Thank you for answers. Let me check if I got this right.

On Monday, June 10, 2013 13:23:26 Steven Schveighoffer wrote:
shared was supposed to infer memory barriers, but AFAIK, it 
doesn't do

that. Not sure it ever will.


So, my first impression about what shared should do (no low-level 
races at all) was correct, but the things didn't work out that 
way. So that kind of doesn't solve the issue with low-level 
races, which IIRC Andrei considers the biggest crime a language 
type system can commit. And the likely (brand-new) solution to 
that is


On Monday, 10 June 2013 at 14:49:27 UTC, Dmitry Olshansky wrote:
Now there was a discussion on it recently which indicates that 
shared data might lose it's built-in ops to prevent confusion 
and require folks to just use core.atomic directly for 
lock-free or alternatively cast+mutex for lock-based.


which seems reasonable too.

So, is my understanding correct? If yes, why the path with memory 
barriers was announced, but not taken?


Failed to sort range

2013-05-28 Thread Sergei Nosov

Hi!

I'm trying to implement an array, which uses malloc to allocate 
memory. Also, I want to implement a random access range interface 
for it.


That went pretty well, until I tried to sort it. Sorting function 
asserted Failed to sort range of type Array!(int).


I've spent quite some time trying to figure out what's going on 
with no success.


The implementation can be found at:
https://gist.github.com/snosov1/5662471

I used
DMD64 D Compiler v2.062 and
LDC - the LLVM D compiler (trunk): based on DMD v2.062 and LLVM 
3.2svn
on Ubuntu. Phobos version was the one that came with the dmd 
compiler.


Does anyone have any ideas what's wrong with the code I've 
provided?


Re: Failed to sort range

2013-05-28 Thread Sergei Nosov

On Tuesday, 28 May 2013 at 12:57:12 UTC, Sergei Nosov wrote:

Hi!

I'm trying to implement an array, which uses malloc to allocate 
memory. Also, I want to implement a random access range 
interface for it.


That went pretty well, until I tried to sort it. Sorting 
function asserted Failed to sort range of type Array!(int).


I've spent quite some time trying to figure out what's going on 
with no success.


The implementation can be found at:
https://gist.github.com/snosov1/5662471

I used
DMD64 D Compiler v2.062 and
LDC - the LLVM D compiler (trunk): based on DMD v2.062 and LLVM 
3.2svn
on Ubuntu. Phobos version was the one that came with the dmd 
compiler.


Does anyone have any ideas what's wrong with the code I've 
provided?


Forgot to mention, that my hand-made sorting function (simply a 
copy-paste of some quicksort implementation that uses array 
indexing syntax) works just fine


void qSort(alias less, Range)(Range A, int low, int high) {
int i = low;
int j = high;
auto x = A[(low+high)/2];
do {
while(less(A[i], x)) ++i;
while(less(x, A[j])) --j;
if(i = j){
auto temp = A[i];
A[i] = A[j];
A[j] = temp;
i++; j--;
}
} while(i  j);
if(low  j) qSort!less(A, low, j);
if(i  high) qSort!less(A, i, high);
}


Re: Failed to sort range

2013-05-28 Thread Sergei Nosov

On Tuesday, 28 May 2013 at 13:41:19 UTC, bearophile wrote:

Sergei Nosov:

That went pretty well, until I tried to sort it. Sorting 
function asserted Failed to sort range of type Array!(int).


If you take a look a the implementation of Phobos sort, you see 
there is a recently added runtime test mostly meant to catch 
wrongly implemented comparison functions, like q{a = b} 
instead of q{a  b}. Maybe that's the one that has fired. But I 
don't know why.


Bye,
bearophile


I don't think that is the case, since I use the default
comparison function for ints.


Re: Failed to sort range

2013-05-28 Thread Sergei Nosov

Thx, Ali!

1) First, an observation: This Array design conflates the 
concepts of container and range. If there are actual elements 
that are being stored (as opposed to elements being generated), 
it is better tha a range merely provides access to those 
elements. popFront should consume the range, not the container. 
(Unless it is some special type of range with the 
responsibility of removing elements from the container.)


I'm not sure I understand this correctly. Do you mean it's a good 
idea to separate storage and access (via range) to the container? 
Like std.container's containers (heh) have nested Range struct?


2) As a minor comment, back usually means the last element 
but your back_ has the meaning of one-past-the-last element.


Yeah, that's probably a not-so-good name.

3) You have to rethink the indexing as well. opIndex indexes 
directly on vec_:


ref T opIndex(size_t idx) {
return vec_[idx];
}

However, we may be on a slice which has already been sliced 
before (as is the case in quick sort, which 
SwapStrategy.unstable uses). So, I think opIndex should add 
front_ to idx:


ref T opIndex(size_t idx) {
return vec_[front_ + idx];
}

It is a start but still not the solution. Sorry... :/


That's obviously a bug, thanks. But, yeah, not the last one =) I 
updated the gist. And also, replaced the malloc call with new. 
The behavior is the same.




Re: Failed to sort range

2013-05-28 Thread Sergei Nosov

On Tuesday, 28 May 2013 at 18:38:01 UTC, Ali Çehreli wrote:

On 05/28/2013 11:31 AM, Ali Çehreli wrote:

  @property Array!T opSlice(size_t i, size_t j) {
  // ...
  ret.front_ = i;

 I feel like the initialization of front_ above is not right
either.
 Imagine quick sort where we are slicing the right-hand side
of a range
 as [0..10], which has already been sliced before. Setting
front_ to 0
 would be wrong because then opIndex would still be counting
from the
 beginning of the original elements.

My explanation is wrong but I think there is still a bug. 
Imagine we are in the right-hand range that has been sliced as 
[10..$]. Now front_ is 10 and all is good: s[0] provides the 
arr[10] of the original array.


Now imagine our slice again by [5..$]. s_further[0] should 
provide arr[15] of the original array but your setting front_ 
to 5 would unfortunately provide arr[5].


Ali


Yes, exactly.

I believe, the same fix should be applied here: front_ + i, 
front_ + j. It passes the sorting test.


Thank you so much, Ali. Feels like to be back in school again.


Re: Failed to sort range

2013-05-28 Thread Sergei Nosov

On Tuesday, 28 May 2013 at 20:43:32 UTC, Ali Çehreli wrote:

On 05/28/2013 12:47 PM, Anthony Goins wrote:

 sort!(ab, SwapStrategy.stable)(arr);

 This worked for me with the code at your link.

I've noticed that too. The reason that works is because in that 
case it uses Tim Sort. Apparently, the Tim Sort algorithm does 
not expose the bugs that were in the code.


Ali


I believe the issues with opIndex and opSlice caused the bug. 
Now, those are fixed, and I guess it's safe to say that range 
interface is correct.


Although, I remember a discussion in the NG about somewhat 
standardized testing facilities for ranges ( 
http://forum.dlang.org/thread/20130321130858.3ef4@unknown ). 
Precisely the semantic/runtime behavior, to supplement 
isSomeRange templates family. Do you, guys know, was there any 
activities on it?


Re: Possible bug

2013-03-26 Thread Sergei Nosov
On Tuesday, 26 March 2013 at 05:40:00 UTC, Steven Schveighoffer 
wrote:
What you have to do is instantiate the template, then call the 
constructor:


S!(int, 4).S!(byte, 5)(3)

Note that the way templates work in D, a templated struct is 
really a shortcut for:


template S(T)
{
   struct S { ... }
}

So when you instantiate it, S!(int)(5) is really shorthand for 
S!(int).S(5).


Every template is this way.  The shorthand version calls on the 
eponymous member implicitly, that is, the member with the 
same name as the template.  Currently, this only works if there 
is exactly one member.


For example, a function template is really:

template foo(T)
{
   void foo(T t) {...}
}

So doing:

foo!(int)(1)

is really the same as:

foo!(int).foo(1)

It's all outlined here: http://dlang.org/template.html

search for Implicit Template Properties

-Steve


Thx a lot!


Possible bug

2013-03-25 Thread Sergei Nosov

Hi!

This code doesn't compile with dmd v2.062 on Linux_x86_64

pre
struct test(T)
{
T *data_;
this(T *data) {
data_ = data;
}
}

void main()
{
int *cptr = null;
test!int hello = test(cptr);
}
/pre

Error:
dmd test.d
test.d(12): Error: struct test.test does not match any function 
template declaration. Candidates are:

test.d(2):test.test(T)
test.d(12): Error: struct test.test(T) cannot deduce template 
function from argument types !()(int*)


Everything's fine if I specify parameters explicitly:
pre
test!int hello = test!int(cptr);
/pre


Re: Possible bug

2013-03-25 Thread Sergei Nosov

On Monday, 25 March 2013 at 14:12:17 UTC, bearophile wrote:

Sergei Nosov:


Everything's fine if I specify parameters explicitly:
pre
test!int hello = test!int(cptr);
/pre


Some persons have proposed alternative designs, but D is 
working as currently designed here... Unlike template 
functions, templated structs don't infer the type.


Bye,
bearophile


Thx, is there any good rationale?


Re: Possible bug

2013-03-25 Thread Sergei Nosov

Thank you, guys!

You made the matters clear to me!

It would be an interesting enhancement over C++.

Although, Steven, I didn't quite understand what you're 
suggesting to use in case of 
templated-struct-templated-constructor


Explicitly specifying struct parameters is ok. Deducing 
constructor parameters from arguments is also ok. But what if not 
all of the constructor parameters may be deduced? E.g. one of 
them is an int?


Would it be a no-no case? or should we merge the lists in one? or 
should we use two bangs? S!(int, 4)!(byte, 5)(3) ? =)