October 05, 2008
On 2008-10-05 01:55:43 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:

> That will do a runtime check and throw if x is negative. That's unprecedented for an implicit cast, so I was thinking of defining a
> universal "unsigned" template function that does the check:
> 
> auto y = sqrt(unsigned(x));

Well, at this point I would prefer if it was a contract. Having to explicitly convert to unsigned just makes it harder than necessary.

Throwing may be unprecedented for implict casts, but it is standard for contracts using assertions. So I think it would be okay to implicit cast and assert the value is non-negative (which would be equivalent to enforcing a contract).

But then, shouldn't sqrt(-1) give you NaN, or i?

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

October 05, 2008
Michel Fortin wrote:
> On 2008-10-05 01:14:17 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
> 
>> I don't favor "." any more than the next guy, but I am glad there is awareness of how unfit a choice "!" is. If you have any ideas, please post them! Ah! I! Exclaimed! Again!
> 
> Hum, I don't think we have much choice, it'll have to be something in this lot:
> 
>     Positive!(real)(joke);
>     Positive.(real)(joke);
>     Positive#(real)(joke);
>     Positive@(real)(joke);
>     Positive&(real)(joke);
>     Positive`(real)(joke);
>     Positive´(real)(joke);
>     Positive^(real)(joke);
>     Positive¨(real)(joke);
>     Positive\(real)(joke);
> 
> Anything else I forgot?
> 
> Or we could use special delimiter characters:
> 
>     Positive<real>(joke);
>     Positive“real”(joke);
>     Positive«real»(joke);
>     Positive#real@(joke);
> 
> Each having its own problem though.
> 
> My preference still goes to "!(".
> 
> - - -
> 
> The ".(" syntax makes me think more of something like this:
> 
>     void func(T, alias methodOfT, A...)(T obj, A args)
>     {
>         obj.(methodOfT)(args);
>     }
> 
> which I which I could do. If methodOfT was a string, I suppose I could use string mixins, but it pushes diagnostics about misnamed methods further in the template and requires adding quotes to the template parameter when instanciating.
> 

Argh, actually I once have a strong desire making

  f«T»(x);

a valid construct, and to workaround that « and » can't be easily typed you could substitute it with

  f\<T\>(x);

---

Anyway, I think the .() syntax is not as good as !() because the . is pretty hideous before another punctuation mark (which may be a good thing, I don't know), and one could easily miss it.

And even if .() is allowed, please don't remove !() -- it will break significantly many code, and it doesn't cause any ambiguity either (unlike .func() vs .prop).
October 05, 2008
I would prefer a more general, ADA like, solution.

// ADA
SUBTYPE Natural IS Integer RANGE 0 .. Integer'Last;
SUBTYPE NonNegFloat IS Float RANGE 0.0 .. Float'Last;
and also :
SUBTYPE CapitalLetter IS Character RANGE 'A' .. 'Z';


just my 2 euro cents;
Bjoern

October 05, 2008
Andrei Alexandrescu wrote:

>> Maybe create the templates as a back end using whatever name, and then create
>> typedefs/aliases for ufloat, udouble, ureal?  This would definitely be consistent
>> with ints and easy to remember.
> 
> I think that's a great idea. So, the question becomes: how do people feel about using ufloat, udouble, and ureal?

I'll just insert my usual "real is not a type, but an alias"...

At least udouble is easier to understand than Positive.(double)

--anders
October 05, 2008
Walter Bright wrote:
> Andrei Alexandrescu wrote:
>> About proliferation of types: I don't think that follows at all. Math found positive numbers special enough to dedicate them a special notation (|R with subscript "+"). There's also a special notation for nonzero real numbers (|R with superscript "*"). There is no special notation for any of the sets you mentioned. That is bound to mean something.
> 
> I'm not a math major. But in college I took 4 years of math, up through integration in the complex plane and branch cuts (which I never did properly understand <g>). Every engineering/physics class was a math class. I never saw this notation. I am not suggesting it doesn't exist, just that it became commonplace fairly recently, or that it isn't commonplace at least at the undergraduate level. This plays into the numbers issue you mentioned.

Probably they'd used (0, +∞) and [0, +∞) instead.

---

BTW, negative real numbers can also be indicated as ℝ⁻ (R^- if Unicode is not supported). Is it now special enough to deserve a Negative!() template? :p

I think these sign checking should be done through contracts or "conditional template" (? whatever it's called; I haven't used one of these yet) instead. Unless you can runtime check that

  Positive!(double) x = 6;
  Positive!(double) y = 12;
  Positive!(double) z = void;
  z = x - y;  // raises error.
  Positive!(double) w;
  din.readf("%g", &w);  // raises error if user enters negative number.

But I don't think uint, etc now even do these checks.
October 05, 2008
I don't like using "." for template instantiation. The tokenizer in my eyes clearly separates constructs at ".". On the other hand, "!" as a graphical character is more 'filled', thus doesn't separate the identifier and arguments that much visually.

foo.bar          <-  obviously member access
foo.(bar, baz)   <-  multiple member access?

... It looks like it should yield a tuple containing bar and baz :P


foo!(bar, baz)   <-  distinct, no issue.


As for the other queries, I like how template instantiation stands out right now with the exclamation mark. I would not like to have compile-time and run-time merged visually in code. And I don't forget to put the exclamation mark there when programming templates.

Let's also keep in mind what Ary said, that using "." will cause problems for IDEs.

What's the point in pretending that run-time is the same as compile-time? You can't instantiate compile-time constructs with run-time arguments, the costs are very different, too. Heck, when I see too many "!" in the code, it indicates that there may be a design issue and some massive bloat involved. I would not like this additional insight into the code removed from my eyes.


-- 
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode
October 05, 2008
Christopher Wright Wrote:

> Andrei Alexandrescu wrote:
> > The problem I see with "!" as a template instantiation is not technical. I write a fair amount of templated code and over years the "!" did not grow on me at all. I was time and again consoled by Walter than one day that will happen, but it never did. I also realized that Walter didn't see a problem with it because he writes only little template code.
> > 
> > I didn't have much beef with other oddities unique to D. For example, I found no problem accommodating binary "~" and I was wondering what makes "!" different. I was just looking at a page full of templates and it looked like crap.
> > 
> > One morning I woke up with the sudden realization of what the problem was: the shouting.
> 
> Not only that, but typing it is annoying. First you need to put the right pinky on the shift key, which is a long reach; then you need to put the left pinky on the 1 key, which is a long reach. Then you need to move your left pinky all the way back to the left shift key, which is a short reach, and move your right ring finger up to the 9 key.
> 
> It's a lot of reaching and back and forth.
> 
> But I don't favor '.' since it's already used.

I don't like the idea of '.' either. I currently like the '!'. I am not the best at templates and making templates similar to function call (looks like each other) would make templating so much harder. It should have something that lets you know right off that it's a template. Do you really want a template looking like a function. That has potential to get confusing as your brain argues just at a glance over if a function is called and supplied parameters most functions wouldn't accept or is it a template and the list afterwards is the stuff supplied to the function (I don't remember ever passing to a function (real, real) so looking at that and having my brain think about "OH!" that's why the function call isn't working and the code won't compile, it's because you were dumb enough to supply types instead of values is not very intuitive).

I like the '!' and don't look forward to seeing it changed but if it was to be changed, I'd prefer it not to be a '.' but maybe something along the line of a colon (':') because it doesn't show a function call. I can't remember ever using a ':' in my code except for that import this : function2 type stuff so I think this would be a good idea versus the '.'

Lester L. Martin II

October 05, 2008
On Sun, 05 Oct 2008 03:35:57 +0100, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> Hello,
>
>
> (Background: Walter has kindly allowed ".()" as an alternative to the ugly "!()" for template argument specifications.)
>
I can't believe you posted this to this newsgroup expecting the bit about the positive
template to be the focus of attention. As soon as I saw it, I anticipated the usual
'enflamed discussion'. Didn't you? or was that part of the plan?
Anyway, I am glad some people did eventually get back to your main question.

[snip]
>
> In order to get things really started, there's already been an exchange with Walter on the matter. His reply was (I haven't asked for permission, but I'm pretty sure he'd agree making it public):
>
> ==============
> Honestly, I wouldn't use it. I'd rather have an in contract for sqrt that asserts the argument is positive. Also, this opens the door to Negative, NegativeOrZero, ZeroOrInfinity, Odd, Even, Prime, SixOrFifteen, etc.
> ==============
>
> My answer to that was:
>
> ==============
> About contracts: Let me explain how I think that's inferior to Positive in two ways.
>
> 1. Enough functions are defined on positive numbers only, to justify factoring that contract out of the functions themselves.
>
> 2. The efficiency perk is that when using several such functions together, there's only one check; once in Positive-land, no more checks are necessary.
>
> About proliferation of types: I don't think that follows at all. Math found positive numbers special enough to dedicate them a special notation (|R with subscript "+"). There's also a special notation for nonzero real numbers (|R with superscript "*"). There is no special notation for any of the sets you mentioned. That is bound to mean something.
> ==============
>
> I'm interesting in further arguments. This feature is a numbers issue (pun not intended), meaning it will be any good only if enough people find it useful enough to actually use it in their own code and libraries, therefore building momentum behind it.
>
>
> Andrei

As at least one other pointed out.
  * means x >= 0 i.e. non negative
  + means x > 0 i.e. strictly positive

I think it is useful to support sub-typing as you suggest. Moreover, I would
like to see more subtypes. Including things like Negative NegativeOrZero, and Odd
or Even but not six of fifteen. Prime will be too expensive to check but it might
still be useful. Its probably better to leave that to people to create when they
find it useful.

Generalised range restricted sub-types would be a real boon.

I don't see what the problem is with proliferating types. If you have a function
that works on a restricted range then declaring that makes sense.

Regarding the name I have no good suggestions. There is "Unsigned" which is a C-ism
that is out of kilter with the mathematical intent. There is "Cardinal" which is
under rated outside of Modula derived languages but includes only whole numbers.
Actually I think "Cardinal" would be a useful addition in its own right.

I think subtyping is orthogonal to declaring a contract. Contracts apply to
functions whereas this is a type declaration.
Also you can use it to be more concise in your contracts. To declare that two non-negative
numbers are greater than each other you could just write:

  NonNegative!(x) > NonNegative!(y)

If this is going to end up in a std library why is it a problem if few people use it?
It is better that it is there and that people are aware of it than that people go down
separate paths in solving the same problem at a later stage. Perhaps a more
interesting question is how will you be using it?

A second use I can see is selecting two different implementations at compile time.
A (possibly faster) one for when the contract is supported and a slower or just different
one when the type contract is not met.

Going back to the sqrt example. Do you propose to change the library declaration to

 NonNegative!(numberType) sqrt( NonNegative!(numberType) X, NonNegative!(numberType) Y);

Presumably changes like this are the real reason you want more feedback?

My understanding of what you propose is:

This is slightly less readable than using contracts but it is a more precise definition
of the interface.

Implicit type conversion would test the positivity in calls at compile time if possible
but otherwise at runtime when necessary.
The internal implementation of square root would not use the type constructor as it knows it answer
will be positive. It could end with a cast to NonNegative to avoid the unnecessary test or
more likely always be using NonNegative numbers inside.
Internal temporaries would be checked at compile time (when initialised to a compile time constant value)
so there would be no added cost to implementing sqrt only using it with values that might
be negative.

If my understanding is correct you are proposing this mainly because unlike contracts,
templates are checked by the compiler at compile time.
I suspect that is the real problem. I and others have previously tried to argue for compile
time checkable contracts.
Another advantage of compile time contracts is that you can design and test arbitrary new
categories of type without having to add new type specifiers to the language. I'm thinking about
const and pure here. Though pure would require functions to have visible compile time attributes
(as opposed to the purely invisible ones which must exist internally) which is another kettle of fish.

Regards,

Bruce.



October 05, 2008
On Sun, 05 Oct 2008 09:04:37 +0100, Michel Fortin <michel.fortin@michelf.com> wrote:

> On 2008-10-05 01:55:43 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
>
>> That will do a runtime check and throw if x is negative. That's unprecedented for an implicit cast, so I was thinking of defining a
>> universal "unsigned" template function that does the check:
>>  auto y = sqrt(unsigned(x));
>
> Well, at this point I would prefer if it was a contract. Having to explicitly convert to unsigned just makes it harder than necessary.
>
> Throwing may be unprecedented for implict casts, but it is standard for contracts using assertions. So I think it would be okay to implicit cast and assert the value is non-negative (which would be equivalent to enforcing a contract).
>
> But then, shouldn't sqrt(-1) give you NaN, or i?
>

Depends on the type of argument.

For normal integers it should balk at compile time if possible and assert/throw if necessary
For complex types i would make sense.
For IEEE real numbers the specification probably mandates some behaviour such as NaN. Anyone read it recently?
October 05, 2008
On Sun, 05 Oct 2008 11:48:35 +0100, Tom S <h3r3tic@remove.mat.uni.torun.pl> wrote:

> I don't like using "." for template instantiation. The tokenizer in my eyes clearly separates constructs at ".". On the other hand, "!" as a graphical character is more 'filled', thus doesn't separate the identifier and arguments that much visually.
>
> foo.bar          <-  obviously member access
> foo.(bar, baz)   <-  multiple member access?
>
> ... It looks like it should yield a tuple containing bar and baz :P
>
That is actually a very nice idea and a good syntax for it.