June 24, 2015
On 24/06/15 09:03, Tofu Ninja wrote:

> If nouns are the convention we want, then one option might be to just
> introduce one function "capitalizer" and have the case type be an
> additional argument to the function, aka: capitalizer!lower/
> capitalizer!upper/ capitalizer!title. Or lowerCapitalizer/
> upperCapitalizer might work as well.

I don't like that. There's a method in Ruby on Rails that's called "capitalize". It converts the first letter to a capital and the remaining ones to lower case.

-- 
/Jacob Carlborg
June 24, 2015
On 24/06/15 07:20, Jonathan M Davis wrote:

> If we want to be consistent with the likes of splitter, then they should
> be something more like lowerCaser and upperCaser (though caser isn't
> really word, and AFAIK, there is no noun for something which changes the
> case of a letter).

How is that consistent? The original names are toLower/toUpper, not lowerCase/upperCase. So it should be something like toLowerer but that clearly doesn't work.

-- 
/Jacob Carlborg
June 24, 2015
On Wednesday, 24 June 2015 at 13:27:17 UTC, Vladimir Panteleev wrote:
> On Tuesday, 23 June 2015 at 23:58:07 UTC, Jeremy Powers wrote:
>> I actually don't think having separate threads for each name is the best solution.  May be better to get them all listed in one place, and see if a consistent naming system can emerge.
>
> I looked through std.range and std.algorithm and created this page:
>
> http://wiki.dlang.org/Naming_conventions

BTW, as for eager/mutating functions, they are almost all verbs:

== std.algorithm ==
sort
schwartzSort
largestPartialIntersection
bringToFront
copy
fill
moveAll
moveSome
remove

== std.array ==
join
replace
split
replicate

June 24, 2015
On 24/06/15 03:03, Adam D. Ruppe wrote:

> Moreover, with this, some old code will *automatically* be upgraded to
> laziness without needing to change at all too. Tell me that doesn't at
> least tempt you!

I like it :) But I fear it will break code and Walter won't like that.

-- 
/Jacob Carlborg
June 24, 2015
On 24/06/15 13:28, Jonathan M Davis wrote:

> It won't break isSomeString. isSomeString will continue to work the
> same. What it will mean is that the result of toLower won't pass
> isSomeString anymore, and if you pass it to a range-based function which
> has an overload for strings, it won't match it and will be treated the
> same as a range like FilterResult and not get the string optimizations.
> If you want it to actually be a string, then you'll need to use
> to!string on it (even std.array.array wouldn't work, since that would
> convert it to dchar[], not string).
>
> So, that could be a reason why this isn't a great idea, but it once
> again highlights why having autodecoding is a bad idea, and it shows
> that as we increase how much we're doing with functions which return
> lazy ranges, the cost of having autodecoding will only increase, because
> we'll being dealing with strings directly less and less.

Can't we update isSomeString to detect this use case?

-- 
/Jacob Carlborg
June 24, 2015
On Wednesday, 24 June 2015 at 13:31:00 UTC, Jacob Carlborg wrote:
> How will that make things better? A user will see both toLower and toLowerCase can think: "What the h*ll is the difference between these to functions".

Absolutely.

I don't even like names that are just kinda similar. Ruby, for example, has `chop` and `chomp`. What's the difference? idk, I have to look it up. (chop will also remove non-newlines from the end)


At least toLower vs toLowerCase would have different types, so the compiler can help explain which is which, but really, ugh.


BTW here's another outside-the-box idea.

eager = toLower
lazy = map!lowercase


Yes, just provide a function that works on chars and reuse map for laziness.
June 24, 2015
On Wednesday, 24 June 2015 at 13:40:28 UTC, Vladimir Panteleev wrote:
> On Wednesday, 24 June 2015 at 13:27:17 UTC, Vladimir Panteleev wrote:
>> On Tuesday, 23 June 2015 at 23:58:07 UTC, Jeremy Powers wrote:
>>> I actually don't think having separate threads for each name is the best solution.  May be better to get them all listed in one place, and see if a consistent naming system can emerge.
>>
>> I looked through std.range and std.algorithm and created this page:
>>
>> http://wiki.dlang.org/Naming_conventions
>
> BTW, as for eager/mutating functions, they are almost all verbs:
>
> == std.algorithm ==
> sort
> schwartzSort
> largestPartialIntersection
> bringToFront
> copy
> fill
> moveAll
> moveSome
> remove
>
> == std.array ==
> join
> replace
> split
> replicate

Which is sensible. A range is an object that performs an action, an eager function is the action itself.
June 24, 2015
On Wednesday, 24 June 2015 at 01:04:01 UTC, Adam D. Ruppe wrote:
> We disagreed on this on irc, but I ask you to consider the following which limits the code breakage a lot more than my first proposal in chat:
>
> [...]

Some thoughts:

- I think the implementation is better done through composition (i.e. a function that takes any range, and returns a type that works like that range but also allows implicit conversion to string. Not sure how feasible this is, maybe multiple alias this will help.

- On the performance side, one point is that this grows the size of the struct by two machine words (string's .ptr and .length). This type is likely to be passed by value through function parameters, too.

- Another perf. issue is that this introduces additional cost every time the implicit conversion to string is done (you need to at least check if the string value has been calculated).

Ultimately I think it's interesting but I defer the final answer to Walter/Andrei, and I think I can predict their answer.
June 24, 2015
On Wednesday, 24 June 2015 at 13:43:50 UTC, Adam D. Ruppe wrote:
> Yes, just provide a function that works on chars and reuse map for laziness.

Actually, this might not quite work because toLower/Upper might need to transform two characters at once in some alphabets. Ugh.

still I do generally like the idea of getting users used to composing building blocks themselves. We provide the pieces and the docs tell them how to put it together. If foo().bar() works, no need to always write a new foobar() function too.
June 24, 2015
On Wednesday, 24 June 2015 at 13:37:35 UTC, Jacob Carlborg wrote:
> On 24/06/15 07:20, Jonathan M Davis wrote:
>
>> If we want to be consistent with the likes of splitter, then they should
>> be something more like lowerCaser and upperCaser (though caser isn't
>> really word, and AFAIK, there is no noun for something which changes the
>> case of a letter).
>
> How is that consistent? The original names are toLower/toUpper, not lowerCase/upperCase. So it should be something like toLowerer but that clearly doesn't work.

It's consistent with the naming scheme used by functions like splitter, joiner, or filter (though in filter's case, it's both a verb and a noun). The function is named after the noun that does the operation rather than the operation - e.g. the verb is split, but the one that does the splitting is the splitter. So, in the case of toLower and toUpper, what you're manipulating is the case, so following that naming scheme, a lower caser would be what did the to lower case operation, and an upper caser would be what did the to upper case operation. Now, that's ugly since caser isn't a real word (there really isn't a noun for something which changes a letter to uppercase or lowercase), but it's following the same scheme as splitter. Conversely, we could go with lowerer and upperer, though those are pretty ugly and nonsensical too, but having to in the name doesn't follow the convention that we use with functions like splitter or joiner, so toLowerer like you suggest wouldn't fit.

All in all, because there is no noun or object which changes the case of letters (it's really just an operation), following the naming scheme of functions like splitter is bound to be ugly. But it _is_ making them consistent with what we've done with the names of existing functions when we've made lazy versions of them (e.g. split -> splitter, and join -> joiner).

- Jonathan M Davis