Why do I despise python

Programming, for all ages and all languages.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Why do I despise python

Post by Solar »

I guess we're both right to some extend. Yes, perhaps today's software world is dominated by web frontends and user apps.

But...

...those aren't usually written in C or C++ (which was what spawned this discussion about the semantics of . versus ->).

In the places where you do want to employ C/C++, cache hit / chache miss usually does matter. ;-)
Every good solution is obvious once you've found it.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Why do I despise python

Post by Schol-R-LEA »

Solar wrote:I guess we're both right to some extend. Yes, perhaps today's software world is dominated by web frontends and user apps.

But...

...those aren't usually written in C or C++ (which was what spawned this discussion about the semantics of . versus ->).

In the places where you do want to employ C/C++, cache hit / chache miss usually does matter. ;-)
OK, yes, that is true. Somewhat less so when talking about Python, but topic drift is a thing and the specific matter at hand was the C/C++ member indirection operator.

I am still not convinced that Brendan's point about cache misses and language design (specifically, his disdain for letting the compiler choose how to lay it out) really is correct, nor do I think it is even relevant to QByte's complaint - what QByte was asserting was that in C, the member indirection operator was redundant, because using ordinary member operator would always be unambiguous.

While I get that Brendan's point is that it gives a clear indication of one place where a cache miss is likely to occur, I find it amusing since, well, it isn't a relevant point - there were no TLB or data cache lines on either the PDP-7 or PDP-11, yet Dennis Ritchie felt that the syntax was necessary anyway. His point is correct for modern systems so far as it goes (even if I don't think that it makes the difference he things it does), but it doesn't speak to why the syntax was there in the first place.

(For newer members, I should add that this is a long-term sticking point between me and Brendan, and between Brendan and several others such as Embryo. In the case of my OS design, the use of code synthesis would make the sort of exact knowledge impossible, as the code to be used doesn't exist until runtime, and may change over the course of the process lifetime. Whether Massalin's approach is feasible on modern DOoOX superscalar CPUs is, as far as I know, an open research question.)

I would add that, even if I took exception to Brendan's particular reply, QByte's statement was... questionable, once one looks at Ritchie's actual motives for that addition - and the fact that he did was noteworthy, as Ritchie was notoriously reluctant to add anything he didn't think absolutely necessary.

So yes, there is a reason why the syntax isn't exactly redundant, even if the desired result can be reached without it. To illustrate, let's take this example code:

Code: Select all

int an_int, an_array[10], *a_ptr;

struct Foo_List {
   int data;
   Foo_List* next;
} *bar;

struct Foo_List baz, quux[16]; 
I assume that QByte's argument is that if bar is a pointer, then the compiler has the information it needs to know that

Code: Select all

bar.data;
needs to indirect the member operator. However, this reasoning has three problems, one related to Ritchie's design philosophy, the second relating to how C handles memory and structs, the third relating to syntactic ambiguity and complications arising from such.

The first problem is simply that it is an exception to the rule that there needs to be a clear separation of operations on the pointer and operations on the object pointed to. This relates directly to the problem Plauger was talking about with Algol-68, which lacked that clarity. You would have to know that bar was a pointer in order to understand this snippet's runtime behavior, which is part of what the member indirection operator makes explicit.

The second part is that C treats everything more or less as chunks of memory, and in the original C especially, typing was seen more as a guideline for how what code to generate for a given operator than as an error checking mechanism. In particular, both arrays are just blocks of memory which the compiler treats as broken into pieces of a given size, and a pointer to a type doesn't differentiate pointing to a single item from pointing to an array. So, if you were to write

Code: Select all

    an_int = an_array;
Then an_int would get the first item of an_array, because as far as the compiler cares, it is just copying one int-size block of memory to another. In older compilers, the same holds true with

Code: Select all

    a_ptr = an_array;
since the compiler didn't care if assigning a pointer to an arbitrary integer might not make sense (and there was no type checking to catch it - deliberately, to allow for literal pointer constants without requiring any special syntax or even an explicit cast).

Now, if memory serves, structs weren't in the language originally, but were added relatively early on (recall that most languages of that time didn't have them at all, and for that matter most didn't have pointers or any other form of indirection, either; most of those which did have indirection, such as Lisp or SNOBOL. used it exclusively and silently). Whenever they came in, they too were just blocks of memory, with struct variables just treated as the base for the member offsets. Arrays of structs were blocks of memory broken up into pieces the size of that struct type.

And once again, a pointer to a struct type didn't differentiate between a single struct and an array of said structs. As far as I know, this is still the case in modern C, though C++ gets a bit more elaborate about it.

Regardless of whether you think this is a good design or not, it fit what Ritchie was trying to accomplish, and despite his later advocacy for it, he originally wasn't expecting anyone outside of Bell Labs to ever see that language. Law of Unintended Consequences, yo.

So the problem here is that in order to use the member operator with struct pointers the way Qbyte seems to want, the language would either need to keep track of what the pointer is pointing to - which would mean added run-time code to keep track of it, and it would always need to include it since the older compilers weren't smart enough to check for special cases - or just ignore the 'problem' just as it did with scalar arrays.

The final problem is that the line

Code: Select all

*bar.next = mumblemumble... ;
is ambiguous. Does the indirection operator apply to bar, or to bar.next? For the approach QByte wants, you would need to use

Code: Select all

(*bar).next
for the former and

Code: Select all

bar.(*next)
for the latter. Is this less gratuitous than

Code: Select all

bar->next
is? I suspect that is a question flame wars could be fought over.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Qbyte
Member
Member
Posts: 51
Joined: Tue Jan 02, 2018 12:53 am
Location: Australia

Re: Why do I despise python

Post by Qbyte »

Schol-R-LEA wrote:The first problem is simply that it is an exception to the rule that there needs to be a clear separation of operations on the pointer and operations on the object pointed to. You would have to know that bar was a pointer in order to understand this snippet's runtime behavior, which is part of what the member indirection operator makes explicit.
It's still clear what the runtime behaviour of the code is, even if at first glance you can't necessarily tell whether the base address of the struct being accessed is given by a pointer or as a constant. In most cases, that isn't something you want to care about, as is the case when dealing with libraries where all the internal details are abstracted away through functions, nor is it something that's difficult to determine if you do need to know. This issue is somewhat orthogonal to the language design as well, since it can be addressed via other means such as hungarian notation (ie, "structptr.member"), syntax highlighting, and so on.
Schol-R-LEA wrote:So the problem here is that in order to use the member operator with struct pointers the way Qbyte seems to want, the language would either need to keep track of what the pointer is pointing to - which would mean added run-time code to keep track of it, and it would always need to include it since the older compilers weren't smart enough to check for special cases - or just ignore the 'problem' just as it did with scalar arrays.
No run-time code is needed, it's handled identically to the way that C's member indirection operator is. You just declare a struct pointer and the compiler knows that whenever you use the dot operator on it, to do the same thing it does with the member indirection operator. This eliminates the pure rendundancy of the latter.
Schol-R-LEA wrote:The final problem is that the line

Code: Select all

*bar.next = mumblemumble... ;
is ambiguous. Does the indirection operator apply to bar, or to bar.next?
That's not ambiguous, because the indirection operator would invariably apply to "next", regardless of whether "bar" is a struct pointer or a just a constant struct address, because in the end, they both mean the same thing, which is the base address given by "bar" + the offset of the member(s). The only difference is that if "bar" is a pointer, its value can change during run-time, whereas the constant address will not. If "bar" is a pointer, the very act of using the dot operator on it automatically dereferences it, and the indirection operator then adds another level which dereferences the final member in the statement. For example:

Code: Select all

struct baz *bar // struct pointer declaration
bar = &foobar // set "bar" to base address of "foobar"
bar.next = &foo // set "next" to the address of "foo"
*bar.next = &foo // set the variable pointed to by "next" to the address of "foo"
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Why do I despise python

Post by Schol-R-LEA »

Qbyte wrote:
Schol-R-LEA wrote:The first problem is simply that it is an exception to the rule that there needs to be a clear separation of operations on the pointer and operations on the object pointed to. You would have to know that bar was a pointer in order to understand this snippet's runtime behavior, which is part of what the member indirection operator makes explicit.
It's still clear what the runtime behaviour of the code is, even if at first glance you can't necessarily tell whether the base address of the struct being accessed is given by a pointer or as a constant. In most cases, that isn't something you want to care about, as is the case when dealing with libraries where all the internal details are abstracted away through functions, nor is it something that's difficult to determine if you do need to know.
While I agree with you on this point, the thing is that it speaks to the entire design ethos of the original C developers, and indeed most developers in the era C was designed in - they didn't see abstraction as desirable. Indeed, the idea of abstracting away details as a design principle (rather than just as a way of making it easier to write more code than you could with assembly language) was sort of an innovative idea at the time (mostly restricted to academic researchers such as Wirth, Dijkstra, Parnas, and Nygaard, and those at places such as Project MAC, Xerox PARC, and Circle Graphics Habitat), one which wasn't widespread until more than a decade later. While the researchers at Bell Labs would have been familiar with the idea, they wouldn't have seen it as relevant to systems programming, which was what C was meant for.¹

The whole point of C was to be as transparent and explicit as possible, avoiding abstraction as much as it could. This is still the facet of it that appeals to most of it's advocates, really. It is meant to be just one step removed from assembly language, high level enough to be portable and make the algorithms easy to see but otherwise not hiding anything.

This made a certain amount of sense for a systems programming language in 1970. I don't think it makes nearly as much sense in light of the better understanding of software design developed in the forty years since (our understanding of it today is still rudimentary, mind you, but further along than it was then nonetheless). And even in 1970 it made no sense for most user applications.


Footnote
1. it is also worth mentioning again that it was only meant for a sort in house toy OS, at that, one made as a time filler to support a single video game during the down time in their schedule following the period when AT&T left the Multics project. Unix only went beyond being a toy when they needed a system to drive a typesetting machine, and then it slowly grew at the lab into something more complete over then next several years, though even in 1976 it was simple enough and easily enough licensed by universities that John Lions - among others - was able to use the source code to teach an OS dev course.

It was the Lions' Commentary, distributed samizdat at universities world-wide in violation of the Unix licensing terms, combined with the licensing of Unix by UC Berkeley and their subsequent modified distribution of the system, that actually made it a force to be reckoned with by the early 1980s. Oh, and contrary to what a lot of people seem to think, Unix and its descendants were never a common OS for business use - at least not until Linux faced off against Windows in the realm of web servers.

In and of itself, this is not a condemnation of Unix - if anything, it is a testament to Thompson's professionalism that he was so careful even on a side project that it could be turned into something serious later on, however flawed it might be as such. But it does shed light on the peculiarities and shortcomings of Unix.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
cappy2112
Posts: 1
Joined: Fri Oct 26, 2018 5:35 pm

Re: Why do I despise python

Post by cappy2112 »

ggodw000 wrote:It has been source of all trouble:

Reason 1.

Code: Select all

>>> a = 1
>>> b = a
>>> a
1
>>> b
1
>>> a = 100
>>> a
100
>>> b
1
>>>
>>>
>>> list1 = []
>>> list1.append(100)
>>> list2 = list1
>>> list1
[100]
>>> list2
[100]
>>> list1.append(101)
>>> list1
[100, 101]
>>> list2
[100, 101]
>>>

Reason 2. When I ask technical question on python forum (first one that comes up on google search), no one can answer, just try this to see if it works, bunch of guesswork. Most of advices don't work.
list2 is simply an alias to list1.
If list1 changes, list2 must reflect that change.
Post Reply