View mode: basic / threaded / horizontal-split · Log in · Help
April 13, 2009
Re: The new, new phobos sneak preview
On 2009-04-12 21:34:47 -0400, Daniel Keep <daniel.keep.lists@gmail.com> said:

> Michel Fortin wrote:
>> Which makes me think of one thing: why "isBounded" instead of plain and
>> simple "bounded"? Ranges don't respond to "isEmpty": they have "empty"
>> instead.
>> 
>> I think it is time to establish some kind of standard for naming things,
>> and then follow it. Something a little like Cocoa's Coding Guidelines
>> comes to mind:
>> 
>> <http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html>

You 
>> 
> mean http://digitalmars.com/d/1.0/dstyle.html ?  That said, the
> "Naming Conventions" section is actually about formatting names, not
> choosing them.

Nice.

Indeed, I think there should be a section about choosing proper names 
in that document.


> One major advantage Cocoa has over D is that argument names seem to be
> part of the function's name.  For example, this call:
> 
>   sendAction(aSelector, anObject, flag);
> 
> appears to be written like so in Objective C:
> 
>   [sendAction: aSelector to: anObject forAllCells: flag];
> 
> To be honest, there are times I almost wish we could not only name
> arguments on the caller side, but demand that they're named in the
> definition.
> 
>   void sendAction(SEL, Object to, extern bool forAllCells);
> 
>   sendAction(aSelector,
>     to: anObject,         // optional
>     forAllCells: true);   // required

It works in Cocoa because it's part of the method name (the actual 
method name for the above is "sendAction:to:forAllCells:").

Your idea doesn't work well with function overloading and passing 
function arguments using tuples. In D, the method mangled name includes 
the argument types to support that, so you can use an enum instead and 
get mostly the same result:

	enum ForCells { ALL, SELECTION }

	setAction(aSelector, anObject, ForCells.ALL);

Hum, that'd be a good pattern to add to a programming guideline document.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/
April 13, 2009
Re: The new, new phobos sneak preview
Looking at the documentation, I found std.range.isForwardRange.  I had a
look at the implementation, and it basically just checks to make sure
you can do this:

> R r1;
> R r2 = r1;

How do you construct an input range which is not also a forward range?
For structs, you can't prevent that second line from working, except by
throwing an exception in postblit (which the test won't notice).  For
classes, you have no control over direct assignment.

Here's a practical example: I'm playing with a program that will parse
the output of DMD to find out module imports.  I want to expose this
list of imports as a range.  However, this range is NOT resumable since
you can't seek a program's captured stdout backwards; copying the file
handle certainly isn't going to work...

You could probably do it by making sure the range is a struct pointing
to a class which can then take its internal file handle and re-assign it
to a split buffered stream... but I'm never going to use it like that,
so why should I go through all that effort?

Aside from making it possible to forbid assignment (blech), it seems
like there needs to be a way to flag a range as not supporting resuming.
The only reasonable way I can think of off the top of my head would be
something like this:

> template isResumableRange(R)
> {
>     enum bool isResumableRange = isInputRange!(R)
>         && (is(typeof(R.isResumableRange)) && R.isResumableRange)
>         && is(typeof(
>         {
>             R r1;
>             R r2 = r1;
>         }()));
> }
>
> unittest
> {
>     static assert(!isResumableRange!(int));
>     static assert(isResumableRange!(int[]));
>
>     struct A {}
>     struct B
>     {
>         void next();
>         bool empty();
>         int head();
>     }
>     struct C
>     {
>         static enum isResumableRange = true;
>         void next();
>         bool empty();
>         int head();
>     }
>     struct D
>     {
>         static enum isResumableRange = false;
>         void next();
>         bool empty();
>         int head();
>     }
>     static assert(isResumableRange!(A));
>     static assert(isResumableRange!(B));
>     static assert(isResumableRange!(C));
>     static assert(isResumableRange!(D));
> }

I also took the opportunity to rename isForwardRange to isResumableRange
since I can't see how the ability to make a "checkpoint" has anything to
do with being able to go forward.  For example isBidirectionalRange
requires isForwardRange, but what does saving checkpoints have to do
with being able to go in both directions?

 -- Daniel
April 13, 2009
Re: The new, new phobos sneak preview
Michel Fortin wrote:
> Which makes me think of one thing: why "isBounded" instead of plain and
> simple "bounded"? Ranges don't respond to "isEmpty": they have "empty"
> instead.

"bounded(x)" can be read as a predicate ("Is x bounded?"), an assertion
("x is bounded, so treat it as such.") or even a conversion (although I
admit that I can think of a meaningful way to convert an unbounded
sequence into a bounded sequence).  "isBounded(x)" is unambiguous.


-- 
Rainer Deyke - rainerd@eldwood.com
April 13, 2009
Re: The new, new phobos sneak preview
Michel Fortin wrote:
> On 2009-04-12 11:09:51 -0400, Lars Kyllingstad 
> <public@kyllingen.NOSPAMnet> said:
> 
>> Andrei Alexandrescu wrote:
>>> Lars Kyllingstad wrote:
>>>> I think isInfinite!() should be called isInfiniteRange!(). The 
>>>> current name is, in my opinion, too general.
>>>
>>> I'm undecided about this (and similar cases). isInfinite sits inside 
>>> std.range, so std.range.isInfinite is clear and 
>>> std.range.isInfiniteRange feels redundant. On the other hand, I don't 
>>> want to use too common symbols because then the user will be forced 
>>> to prefix them whenever they clash.
>>
>> I'm not too worried about name clashes, I just think it sounds wrong. 
>> If R is a range with infinitely many elements, I think it's more 
>> correct to say "R is an infinite range" than to say "R is infinite".
>>
>> As an example of what I mean, let the range R be the sequence 1, 1/4, 
>> 1/9, ...:
>>
>>    alias Sequence!("1/(n*n)", 1) R
>>
>> Then, isInfiniteRange!(R) should obviously yield true. From a 
>> mathematical standpoint, I think the result of isInfinite!(R) is less 
>> obvious. Yes, the range has infinitely many elements, but none of them 
>> are infinite, nor is their sum infinite.
> 
> Perhaps it should be renamed to isUnbounded then.

...except that my example, and indeed any range produced by sequence, 
recurrence, etc. are bounded at one end. Thus the term "infinite range" 
is more precise, and fits in well with the mathematical terms "infinite 
series" and "infinite sequence". Just not "infinite" alone. :)

-Lars
April 13, 2009
Re: The new, new phobos sneak preview
On 2009-04-13 03:56:11 -0400, Rainer Deyke <rainerd@eldwood.com> said:

> Michel Fortin wrote:
>> Which makes me think of one thing: why "isBounded" instead of plain and
>> simple "bounded"? Ranges don't respond to "isEmpty": they have "empty"
>> instead.
> 
> "bounded(x)" can be read as a predicate ("Is x bounded?"), an assertion
> ("x is bounded, so treat it as such.") or even a conversion (although I
> admit that I can think of a meaningful way to convert an unbounded
> sequence into a bounded sequence).  "isBounded(x)" is unambiguous.

I disagree. How adding the "is" it disambiguate between the predicate 
and the assertion? "x.isBounded" reads more like "x is bounded" (the 
assertion) than "is x bounded" (the predicate).

* * *

Assuming the "is" form is less ambiguous for bounded, the same could be 
said about "empty". In fact, not putting "is" in front of "emtpy" is 
even worse since "empty" can also be a verb.

Predicate: "Is x empty?";
Assertion: "x is empty";
Verb: "empty x".

Anyway, more than advocating for or against the "is" prefix, I mostly 
want things to be coherent. If you use "is" for bounded, you should use 
"is" for empty too. That's why I'm suggesting there is a section about 
choosing names in Phobos' Naming Conventions.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/
April 13, 2009
Re: The new, new phobos sneak preview
On 2009-04-13 04:20:32 -0400, Lars Kyllingstad 
<public@kyllingen.NOSPAMnet> said:

> ...except that my example, and indeed any range produced by sequence, 
> recurrence, etc. are bounded at one end. Thus the term "infinite range" 
> is more precise, and fits in well with the mathematical terms "infinite 
> series" and "infinite sequence". Just not "infinite" alone. :)

Indeed.

And since the thing in the argument is indeed a range, I'd use infinite 
alone in the function name. That way, if you build something which 
isn't a range but still represent a sequence, it can have this part of 
the interface in common.

In a language that doesn't support overloading (such as C or 
Objective-C), I'd be in favor of keeping the "range" suffix to 
differenciate the function from other functions applying to other kinds 
of arguments. In D, or C++, which support overloading, I'm in favor of 
skipping the argument type suffix.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/
April 13, 2009
Re: The new, new phobos sneak preview
Lars Kyllingstad wrote:
> Michel Fortin wrote:
>> On 2009-04-12 11:09:51 -0400, Lars Kyllingstad 
>> <public@kyllingen.NOSPAMnet> said:
>>
>>> Andrei Alexandrescu wrote:
>>>> Lars Kyllingstad wrote:
>>>>> I think isInfinite!() should be called isInfiniteRange!(). The 
>>>>> current name is, in my opinion, too general.
>>>>
>>>> I'm undecided about this (and similar cases). isInfinite sits inside 
>>>> std.range, so std.range.isInfinite is clear and 
>>>> std.range.isInfiniteRange feels redundant. On the other hand, I 
>>>> don't want to use too common symbols because then the user will be 
>>>> forced to prefix them whenever they clash.
>>>
>>> I'm not too worried about name clashes, I just think it sounds wrong. 
>>> If R is a range with infinitely many elements, I think it's more 
>>> correct to say "R is an infinite range" than to say "R is infinite".
>>>
>>> As an example of what I mean, let the range R be the sequence 1, 1/4, 
>>> 1/9, ...:
>>>
>>>    alias Sequence!("1/(n*n)", 1) R
>>>
>>> Then, isInfiniteRange!(R) should obviously yield true. From a 
>>> mathematical standpoint, I think the result of isInfinite!(R) is less 
>>> obvious. Yes, the range has infinitely many elements, but none of 
>>> them are infinite, nor is their sum infinite.
>>
>> Perhaps it should be renamed to isUnbounded then.
> 
> ...except that my example, and indeed any range produced by sequence, 
> recurrence, etc. are bounded at one end. Thus the term "infinite range" 
> is more precise, and fits in well with the mathematical terms "infinite 
> series" and "infinite sequence". Just not "infinite" alone. :)
> 
> -Lars

Finally! I was waiting for someone to make this point. "Bounded" would 
be closer to "having values within a finite interval".

Andrei
April 13, 2009
Re: The new, new phobos sneak preview
Michel Fortin wrote:
> I disagree. How adding the "is" it disambiguate between the predicate
> and the assertion? "x.isBounded" reads more like "x is bounded" (the
> assertion) than "is x bounded" (the predicate).

Method syntax usually leads to incorrect word order.  "a.b(c)", should
not be read as "a does b to c", but as "Computer, do b to a and c.".
It's a command to the computer, not a statement.  In that context,
"isBounded(x)" reads as "Computer, is x bounded?".

I'm also in favor of "asBounded(x)" (treat x as a bounded range) and
"toBounded(x)" (convert x to a bounded range, not really applicable for
"bounded").

> Anyway, more than advocating for or against the "is" prefix, I mostly
> want things to be coherent. If you use "is" for bounded, you should use
> "is" for empty too. That's why I'm suggesting there is a section about
> choosing names in Phobos' Naming Conventions.

Agreed.


-- 
Rainer Deyke - rainerd@eldwood.com
April 13, 2009
Re: The new, new phobos sneak preview
Andrei Alexandrescu wrote:
> Lars Kyllingstad wrote:
>> Michel Fortin wrote:
>>> On 2009-04-12 11:09:51 -0400, Lars Kyllingstad 
>>> <public@kyllingen.NOSPAMnet> said:
>>>
>>>> Andrei Alexandrescu wrote:
>>>>> Lars Kyllingstad wrote:
>>>>>> I think isInfinite!() should be called isInfiniteRange!(). The 
>>>>>> current name is, in my opinion, too general.
>>>>>
>>>>> I'm undecided about this (and similar cases). isInfinite sits 
>>>>> inside std.range, so std.range.isInfinite is clear and 
>>>>> std.range.isInfiniteRange feels redundant. On the other hand, I 
>>>>> don't want to use too common symbols because then the user will be 
>>>>> forced to prefix them whenever they clash.
>>>>
>>>> I'm not too worried about name clashes, I just think it sounds 
>>>> wrong. If R is a range with infinitely many elements, I think it's 
>>>> more correct to say "R is an infinite range" than to say "R is 
>>>> infinite".
>>>>
>>>> As an example of what I mean, let the range R be the sequence 1, 
>>>> 1/4, 1/9, ...:
>>>>
>>>>    alias Sequence!("1/(n*n)", 1) R
>>>>
>>>> Then, isInfiniteRange!(R) should obviously yield true. From a 
>>>> mathematical standpoint, I think the result of isInfinite!(R) is 
>>>> less obvious. Yes, the range has infinitely many elements, but none 
>>>> of them are infinite, nor is their sum infinite.
>>>
>>> Perhaps it should be renamed to isUnbounded then.
>>
>> ...except that my example, and indeed any range produced by sequence, 
>> recurrence, etc. are bounded at one end. Thus the term "infinite 
>> range" is more precise, and fits in well with the mathematical terms 
>> "infinite series" and "infinite sequence". Just not "infinite" alone. :)
>>
>> -Lars
> 
> Finally! I was waiting for someone to make this point. "Bounded" would 
> be closer to "having values within a finite interval".
> 
> Andrei

There's a funny thing with floating-point numbers, though.
The range [real.max, real.infinity] contains only two elements, one of 
which is infinity. Is that an infinite range?

It would be helpful to distinguish "contains arbitrary many 
elements"/"length is undefined" from "contains the point at 
infinity"/"includes the maximum representable element for this type".
April 13, 2009
Re: The new, new phobos sneak preview
Daniel Keep wrote:
> Looking at the documentation, I found std.range.isForwardRange.  I had a
> look at the implementation, and it basically just checks to make sure
> you can do this:
> 
>> R r1;
>> R r2 = r1;
> 
> How do you construct an input range which is not also a forward range?

In fact you can't. Thank you for opening this discussion, it's very 
interesting.

In the current system, an input range and a forward range cannot be 
distinguished statically. I wanted to, and initially I thought it's 
possible, but I had to concede defeat. The problem s that forward ranges 
also need to be copyable, otherwise using them is a pain. Then I 
considered defining different symbols for input vs. other ranges, but 
that only makes things harder.

So right now... input range means "one pass, can't save iteration state 
and backtrack" and forward range means "forward pass, can save iteration 
state".

> Aside from making it possible to forbid assignment (blech), it seems
> like there needs to be a way to flag a range as not supporting resuming.
>  The only reasonable way I can think of off the top of my head would be
> something like this:
> 
>> template isResumableRange(R)
>> {
>>     enum bool isResumableRange = isInputRange!(R)
>>         && (is(typeof(R.isResumableRange)) && R.isResumableRange)
>>         && is(typeof(
>>         {
>>             R r1;
>>             R r2 = r1;
>>         }()));
>> }
>>
>> unittest
>> {
>>     static assert(!isResumableRange!(int));
>>     static assert(isResumableRange!(int[]));
>>
>>     struct A {}
>>     struct B
>>     {
>>         void next();
>>         bool empty();
>>         int head();
>>     }
>>     struct C
>>     {
>>         static enum isResumableRange = true;
>>         void next();
>>         bool empty();
>>         int head();
>>     }
>>     struct D
>>     {
>>         static enum isResumableRange = false;
>>         void next();
>>         bool empty();
>>         int head();
>>     }
>>     static assert(isResumableRange!(A));
>>     static assert(isResumableRange!(B));
>>     static assert(isResumableRange!(C));
>>     static assert(isResumableRange!(D));
>> }
> 
> I also took the opportunity to rename isForwardRange to isResumableRange
> since I can't see how the ability to make a "checkpoint" has anything to
> do with being able to go forward.  For example isBidirectionalRange
> requires isForwardRange, but what does saving checkpoints have to do
> with being able to go in both directions?

So essentially we're looking at a symbolic approach - a resumable range 
would need to advertise that. I've used that for isSorted too, and it 
works pretty well.

The remaining question is one of defaults - are most ranges resumable or 
not? I.e., should a range advertise explicitly when it's resumable or 
when it's *not* resumable? I think the safe approach is to go as you 
say: a range ain't resumable unless it explicitly claims to. So if you 
forget stuff, the compiler will remind you.

I'd love to hear more opinions on the topic.


Andrei
5 6 7 8 9 10
Top | Discussion index | About this forum | D home