May 15, 2010
Nick Sabalausky wrote:
> 
> Once upon a time, there was a book called "Writing Solid Code". It seemed that anyone who was an established, respectable programmer swore by it and proclaimed it should be required reading by all programmers. These days, I sometimes feel like I'm the only one who's ever heard of it (let alone read it).
> 
> So much of the book has made such an impact on me as a programmer, that from the very first time I ever heard of a language (probably Python) using "someArray[-5]" to denote an index from the end, I swear, the very first thought that popped into my head was "Candy-Machine Interface". I instantly disliked it, and still consider it a misguided design.
> 
> For anyone who doesn't see the the problem with Python's negative indicies (or anyone who wants to delve into one of the forerunners to great books like "Code Craft" or "The Pragmatic Programmer"), I *highly* recommend tracking down a copy of "Writing Solid Code" and reading "The One-Function Memory Manager" and "Wishy-Washy Inputs", both in the "Candy-Machine Interfaces" chapter.

It's available on safari, for anyone who has a subscription.

http://safari.oreilly.com/
May 15, 2010
Walter Bright <newshound1@digitalmars.com> wrote:

> KennyTM~ wrote:
>> Why a map type (sorted associative array)'s key must start at zero?
>
> You can special case the [0..$], or simply use [] to represent the entire range.

Of course, but assume you want the first 15 elements, what do you do?

-- 
Simen
May 15, 2010
Nick Sabalausky:

>Once upon a time, there was a book called "Writing Solid Code".<

I have not read this book. Thank you for the suggestion, I will read it. There are tons of books about programming and computer science, but the good books are very uncommon, I can probably write a list of less than a dozen titles. So given few years it's easy to read them all.


>It seemed that anyone who was an established, respectable programmer swore by it and proclaimed it should be required reading by all programmers.<

"Writing Solid Code" is a book about programming, but its examples are in C and it's focused on C programming. Today some people write code all day and they don't even know how to write ten lines of C code. Time goes on, and what once was regarded as indispensable, today is less important (in my university the C language is taught only at about the third year, often in just one course and the teacher is not good at all, the code written on the blackboard can be sometimes used by me as examples of how not write C code). This happens in all fields of human knowledge. In practice given enough time, almost no books will be indispensable. Books that are interesting for centuries are uncommon, and they are usually about the human nature (like novels) that changes very little as years pass :-)


>and reading "The One-Function Memory Manager"<

C99 has changed things a bit:

>In both C89 and C99, realloc with length 0 is a special case. The C89 standard explicitly states that the pointer given is freed, and that the return is either a null pointer or a pointer to the newly allocated space. The C99 standard says that realloc deallocates its pointer argument (regardless of the size value) and allocates a new one of the specified size.<

I agree that C realloc is a function that tries to do too many things. C libs are not perfect.


>"Wishy-Washy Inputs",<

Python supports named functions arguments (as C#4, and I hope to see them in D3), this can reduce the bug count because you can state what an argument is at the calling point too.

The code of CopySubStr is bad:
- Abbreviated names for functions (and often variables too) are bad.
- Unless very useful, it's better to avoid pointers and to use normal array syntax [].
- There is no need to put () around the return value in C.


>that many of the cautions in it sound like no-brainers today, like not using return values to indicate error codes.<

Generally in Python when some function argument is not acceptable, an exception is raised. Exceptions are used in D for similar purposes. But in D you also have contracts that I am starting to use more and more.


>So much of the book has made such an impact on me as a programmer, that from the very first time I ever heard of a language (probably Python) using "someArray[-5]" to denote an index from the end, I swear, the very first thought that popped into my head was "Candy-Machine Interface". I instantly disliked it, and still consider it a misguided design.<

A negative value to index items from the end of an array is a bad idea in C (and D), it slows down the code and it's unsafe.

But you must understand that what's unsafe in C is not equally unsafe in Python, and the other way around too is true. A well enough designed computer language is not a collection of features, it's a coherent thing. So its features are adapted to each other. So even if a[5] in Python looks the same syntax as a[5] in C, in practice they are very different things. Python arrays are not pointers, and out-of-bound exceptions are always present. And often in Python you don't actually use a[i], you use something like:

for x in a:
  do_something(x)

As you see there are no indexes visible here (as in D foreach).

What I am trying to say you is that while I agree that negative indexes can be tricky and they are probably too much unsafe in C programs (given how all other things work in C programs), they are not too much unsafe in Python programs (given how all other things work in Python programs). In Python you have to be a little careful when you use them, but they usually don't cause disasters in my code.


>But even for those, it goes into much more detail on the "why" than what you usually hear.)<

It looks like a good book.

Bye,
bearophile
May 15, 2010
Simen kjaeraas wrote:
> Walter Bright <newshound1@digitalmars.com> wrote:
> 
>> KennyTM~ wrote:
>>> Why a map type (sorted associative array)'s key must start at zero?
>>
>> You can special case the [0..$], or simply use [] to represent the entire range.
> 
> Of course, but assume you want the first 15 elements, what do you do?
> 

For a map, does the first 15 elements even make any sense? There is no order in a map.
May 15, 2010
Walter Bright <newshound1@digitalmars.com> wrote:

> Simen kjaeraas wrote:
>> Walter Bright <newshound1@digitalmars.com> wrote:
>>
>>> KennyTM~ wrote:
>>>> Why a map type (sorted associative array)'s key must start at zero?
>>>
>>> You can special case the [0..$], or simply use [] to represent the entire range.
>>  Of course, but assume you want the first 15 elements, what do you do?
>>
>
> For a map, does the first 15 elements even make any sense? There is no order in a map.

std::map is ordered. Other data structures might make more sense.

A weird example would be a trie - slice all from the start
to ['f','o','o'], for instance.


-- 
Simen
May 15, 2010
Simen kjaeraas wrote:
> Walter Bright <newshound1@digitalmars.com> wrote:
> 
>> Simen kjaeraas wrote:
>>> Walter Bright <newshound1@digitalmars.com> wrote:
>>>
>>>> KennyTM~ wrote:
>>>>> Why a map type (sorted associative array)'s key must start at zero?
>>>>
>>>> You can special case the [0..$], or simply use [] to represent the entire range.
>>>  Of course, but assume you want the first 15 elements, what do you do?
>>>
>>
>> For a map, does the first 15 elements even make any sense? There is no order in a map.
> 
> std::map is ordered. Other data structures might make more sense.
> 
> A weird example would be a trie - slice all from the start
> to ['f','o','o'], for instance.


If it's ordered, then why doesn't [0..15] make sense to get the first 15 elements?
May 15, 2010
"bearophile" <bearophileHUGS@lycos.com> wrote in message news:hsm7l9$27nt$1@digitalmars.com...
> Nick Sabalausky:
>
>>It seemed that anyone who was an established, respectable programmer swore by it and proclaimed it should be required reading by all programmers.<
>
> "Writing Solid Code" is a book about programming, but its examples are in C and it's focused on C programming. Today some people write code all day and they don't even know how to write ten lines of C code. Time goes on, and what once was regarded as indispensable, today is less important (in my university the C language is taught only at about the third year, often in just one course and the teacher is not good at all, the code written on the blackboard can be sometimes used by me as examples of how not write C code). This happens in all fields of human knowledge. In practice given enough time, almost no books will be indispensable. Books that are interesting for centuries are uncommon, and they are usually about the human nature (like novels) that changes very little as years pass :-)
>

Yea. The book is heavily C, of course, because C was heavily used at the time. But, I think another reason for all the focus on C is that the typical (at least at the time) C-style and the standard C lib are filled with great examples of "what not to do". ;)

>
>>"Wishy-Washy Inputs",<
>
> Python supports named functions arguments (as C#4, and I hope to see them in D3), this can reduce the bug count because you can state what an argument is at the calling point too.
>

Yea, non-named-arguments-only has been feeling more and more antiquated to me lately.

> The code of CopySubStr is bad:
> - Abbreviated names for functions (and often variables too) are bad.

There are two major schools of thought on that. On one side are those who say full names are more clear and less prone to misinterpretation. The other side feels that using a few obvious and consistent abbreviations makes code much easier to read at a glance and doesn't cause misinterpretation unless misused. Personally, I lean more towards the latter group. (Some people also say abbreviations are bad because the number of bytes saved is insignificant on moden hardware. But I find that to be a bit of a strawman since everybody on *both* sides agrees with that and the people who still use abbreviations generally don't do so for that particular reason anymore.)

> - Unless very useful, it's better to avoid pointers and to use normal array syntax [].

Heh, yea. Well, that's old-school C for you ;)

>
>>that many of the cautions in it sound like no-brainers today, like not using return values to indicate error codes.<
>
> Generally in Python when some function argument is not acceptable, an exception is raised. Exceptions are used in D for similar purposes. But in D you also have contracts that I am starting to use more and more.
>

Yea, since the book was written, exceptions have pretty much become the de facto standard way of handling errors. There are times when exceptions aren't used, or can't be used, but those cases are rare (dare I say, they're "exceptions"? ;) ), and the most compelling arguments against exceptions are only applicable to languages that don't have a "finally" clause.

>
>>So much of the book has made such an impact on me as a programmer, that from the very first time I ever heard of a language (probably Python) using "someArray[-5]" to denote an index from the end, I swear, the very first thought that popped into my head was "Candy-Machine Interface". I instantly disliked it, and still consider it a misguided design.<
>
> A negative value to index items from the end of an array is a bad idea in C (and D), it slows down the code and it's unsafe.
>
> But you must understand that what's unsafe in C is not equally unsafe in Python, and the other way around too is true. A well enough designed computer language is not a collection of features, it's a coherent thing.
>
> What I am trying to say you is that while I agree that negative indexes can be tricky and they are probably too much unsafe in C programs (given how all other things work in C programs), they are not too much unsafe in Python programs (given how all other things work in Python programs). In Python you have to be a little careful when you use them, but they usually don't cause disasters in my code.
>

Python certainly makes the consequences of getting the index wrong less severe than in C, and less likely. But it still stikes me as a bit of a "dual-purpose" input, and therefore potentally error-prone.

For instance, suppose it's your intent to get the fifth element before the one that matches "target" (and you already have the index of "target"):

leeloo = collection[targetIndex-5]

Then, suppose your collection, unexpectedly, has "target" in the third position (either because of a bug elsewhere, or because you just forgot to take into account the possibility that "target" might be one of the first five). With bounds-checking that ensures no negatives, you find out instantly. With Python-style, you're happily givin the second-to-last element and a silent bug.


May 15, 2010
Walter Bright:

>The problem is D already has a lot of syntax. More syntax just makes the language more burdensome after a certain point, even if in isolation it's a good idea.<

This is an interesting topic in general (the following are general notes, not specific of the complement to $). I agree that what can be good in isolation can be less good for the whole syntax ecology of a language.

Some times adding a syntax reduces the language complexity for the programmer. When you have added struct constructors to D2 you have removed one special case, making classes and structs more uniform, removing one thing the programmer/manual has to remember.

Some other times a syntax can mean an about net zero complexity added, because it increases some complexity but reduces some other complexity in the language. For example named function arguments add a little complexity to the language, but they are very easy to learn and if used wisely they can make the code (at the calling point of functions) more readable, and reduce mistakes caused by wrong arguments or wrong argument order. So I see them as good.

There are languages like the Scheme family that have very little amount of syntax. And other languages as C# and C++ that have tons of syntax. There was a time Lisp when was common, but today in practice quite syntax-rich languages seem to have "won". D too is syntax-rich.

So many things show me that programmers are able to use/learn good amounts of syntax (especially when they already know a language with a similar syntax), so syntax is not an evil thing. Yet, today C++ usage is decreasing, maybe even quickly. I think the cause is that not all syntax is created equal.

This is the C++ syntax for an abstract function:
virtual int foo() = 0;
The same in D:
abstract int foo();

Both have a syntax to represent this, but the D syntax is better, because it's specific, it's not used for other purposes, and because it uses a readable word to denote it, instead of of arbitrary generic symbols.

So I think just saying "lot of syntax" as you have done is not meaningful enough. In my opinion programmers are able to learn and use lot of syntax (maybe even more than the amount of syntax currently present in D) if such syntax is:
- Readable. So for example it uses a English word (example: abstract), or it's common in normal matematics, or it's another example of the same syntax already present in another part of the language (example: tuple slicing syntax is the same as array slicing syntax). This makes it easy to remember, easy/quick to read, and unambiguous. If a syntax is a bit wordy this is often not a problem in a modern language used with a modern monitor (so I don't care if 'abstract' is several chars long and a symbol like ^? can be used for the same purpose saving few chars. It's not a true gain for the programmer).
- Specific. Using the same syntax for several different or subtly different purposes in different parts of the language is bad. A specific syntax is something that can't be confused with anything else in the language, it's used for just one purpose and does it well.
- Safe. There is a natural enough way to use it, and the compiler catches all improper usages of it. There are no subtly wrong usages that do something very bad in the program. (This is why I have asked for the compiler to enforce the presence in the code of only the correct symbol strings in the new D2 operator overloading regime. It's too much easy to write something wrong, in my opinion).

Bye,
bearophile
May 15, 2010
On May 16, 10 02:01, Walter Bright wrote:
> Simen kjaeraas wrote:
>> Walter Bright <newshound1@digitalmars.com> wrote:
>>
>>> Simen kjaeraas wrote:
>>>> Walter Bright <newshound1@digitalmars.com> wrote:
>>>>
>>>>> KennyTM~ wrote:
>>>>>> Why a map type (sorted associative array)'s key must start at zero?
>>>>>
>>>>> You can special case the [0..$], or simply use [] to represent the
>>>>> entire range.
>>>> Of course, but assume you want the first 15 elements, what do you do?
>>>>
>>>
>>> For a map, does the first 15 elements even make any sense? There is
>>> no order in a map.
>>
>> std::map is ordered. Other data structures might make more sense.
>>
>> A weird example would be a trie - slice all from the start
>> to ['f','o','o'], for instance.
>
>
> If it's ordered, then why doesn't [0..15] make sense to get the first 15
> elements?

auto a = new OrderedDict!(int, string);
a[-3] = "negative three";
a[-1] = "negative one";
a[0] = "zero";
a[3] = "three";
a[4] = "four";
assert(a[0] == "zero");
return a[0..4]; // which slice should it return?
May 15, 2010
KennyTM~ wrote:
> On May 16, 10 02:01, Walter Bright wrote:
>> Simen kjaeraas wrote:
>>> Walter Bright <newshound1@digitalmars.com> wrote:
>>>
>>>> Simen kjaeraas wrote:
>>>>> Walter Bright <newshound1@digitalmars.com> wrote:
>>>>>
>>>>>> KennyTM~ wrote:
>>>>>>> Why a map type (sorted associative array)'s key must start at zero?
>>>>>>
>>>>>> You can special case the [0..$], or simply use [] to represent the
>>>>>> entire range.
>>>>> Of course, but assume you want the first 15 elements, what do you do?
>>>>>
>>>>
>>>> For a map, does the first 15 elements even make any sense? There is
>>>> no order in a map.
>>>
>>> std::map is ordered. Other data structures might make more sense.
>>>
>>> A weird example would be a trie - slice all from the start
>>> to ['f','o','o'], for instance.
>>
>>
>> If it's ordered, then why doesn't [0..15] make sense to get the first 15
>> elements?
> 
> auto a = new OrderedDict!(int, string);
> a[-3] = "negative three";
> a[-1] = "negative one";
> a[0] = "zero";
> a[3] = "three";
> a[4] = "four";
> assert(a[0] == "zero");
> return a[0..4]; // which slice should it return?

Good question.