General statistics
List of Youtube channels
Youtube commenter search
Distinguished comments
About
Lawrence D’Oliveiro
Lex Fridman
comments
Comments by "Lawrence D’Oliveiro" (@lawrencedoliveiro9104) on "Lex Fridman" channel.
Previous
1
Next
...
All
Probably to avoid the notorious C mistake of using an assignment when you meant to do an equality comparison.
38
Unfortunately, the “zero-overhead” principle has to be abandoned every time you try to do something actually useful with the language. Like anything involving dynamic memory allocation. Or the first time you discover that a “delete” method has to be explicitly declared virtual to avoid certain unpleasant surprises. Which means your class now has to have a vtable. And you wonder, don’t proper OO languages have tables for all their classes?
5
@Danny-sj6es It cannot be used in any expression. Unlike in C, chained assignment is made a special syntactic case.
4
Or how about this: >>> a = 9999 >>> b = 3 >>> a + b is b + a False
2
@keris3920 But C++ doesn’t do λ-calculus, does it? Actually Python does a better job of implementing that than C++ does.
2
@PythonPlusPlus This works for me: return \ {kw : _kw_indexes for kw in keywords for _kw_indexes in (find_occurrences(document, kw),) }
2
Is there such a thing as overuse? For example, instead of if download_limit != None and bytes_downloaded >= download_limit : break I could write if None != download_limit <= bytes_downloaded : break But should I?
1
I detect a PHP programmer ... or maybe Java. . . . . . VBA?
1
Ummm ... who said anything about “==”?
1
Who said I was “confusing” anything with anything?
1
One’s a functional construct, the other is procedural.
1
What “definition” might you be referring to? https://en.wikipedia.org/wiki/Procedural_programming
1
You can change the behaviour of assignment when the LHS is an indexing operation or property access. E.g. a[b] = c gets interpreted as a.__setitem__(b, c) Properties are fun, because they depend on a Python concept called “descriptors”. I’m not sure C++ programmers can understand that. ;)
1
Python’s descriptors also make quite a few other things possible. For example, enums are implemented, not as a special built-in language feature as it is in C, C++ or Java, but just as a library module, written in Python itself. This also makes use of the metaclass feature.
1
@tarashmmurmu8412 In Python 3.5 and later you have the “@” operator to use for the dot product.
1
One quite surprising use of operator overloads with custom Python types is in the “ctypes” standard library module. This is an extensive set of tools for creating “Pythonic” wrappers around shareable libraries that were not written with Python in mind. For example, the ctypes “c_int” type stands for an “int” in the underlying C code. This name can be used as a constructor to wrap a Python integer, to be passed to or returned from C code. But you can also write things like “c_int * 4” to represent an array of 4 ints. This expression returns a new type, which can itself be used as a constructor. Thus, the expression (ctypes.c_int * 4)(1, 2, 3, 4) allocates storage for holding 4 ints, initializes them to the given values, and returns a Python object representing that storage.
1
@keris3920 C++ doesn’t have the “@” operator.
1
Another thing Python lets you overload is built-in functions like len() and abs(). These also dispatch to special methods within the object, for which you can provide custom implementations. For example, in Qahirah, my pure-Python wrapper for the Cairo 2D graphics library, I defined a Vector type, and defined abs(«vector») to return the magnitude of the vector.
1
Another clever point about defining custom indexing with __setitem__ and __getitem__ is that, combined with tuples and an interesting Python syntactic shortcut, they let you implement multidimensional arrays. Thus, instead of “a[(b, c)]”, where the index is the tuple “(b, c)”, you can leave off the parentheses and just write “a[b, c]”. And so on for any number of dimensions. Of course, this applies even if b and c are not numbers.
1
@keris3920 In other words, you can’t really achieve all of that in C++.
1
@keris3920 Don’t get me wrong, C++ has its place. But if Turing-completeness were all there was to it, we would all be programming ... Turing machines.
1
@keris3920 Yes. And a Turing machine, while it works for a lot of mathematical proofs, is not a particularly practical way of carrying out real-world computations. So saying something is “Turing-complete” doesn’t mean you should use it for actual programming.
1
Another overloadable operator Python has, that C++ does not, is “in”, commonly used for membership tests.
1
@keris3920 Yeah, it just slows down compiles instead. And it’s awkward to use, and it doesn’t get rid of having to fall back on the further awkwardness of #define and friends. Python can do everything you can do with your C++-Turing-completeness-at-compile-time, and do it more elegantly. For example, conditional definition of functions and classes: if «cond» : def func() : ... definition 1 for func ... #end func else : def func() : ... definition 2 for func ... #end func #end if where «cond» is the same kind of conditional expression you would write anywhere else.
1
@keris3920 Python doesn’t need to do it at “compile time”, since the full language facilities are available at run time. So you use the same language to do dynamic construction of class and function objects as you would to make use of them, instead of having to resort to different (and clunkier) sub-languages for “compile time” operations. This is reflected in the relative complexities of the languages: the C++ spec is well over 1000 pages now, and continues to grow with every new revision, whereas the entire Python language definition is about an order of magnitude smaller. All the rest of Python’s capabilities come from library modules, building on the core language.
1
@keris3920 If “C++ can do everything at runtime too”, then why does it need separate compile-time and preprocessor sublanguages?
1
@keris3920 Well, you did say “C++ has several Turing complete subsets”. Without the preprocessor, you only have template programming left. What else is there? And adding more and more RTTI is just making C++ more and more like Python, isn’t it? Sure, low-level languages have their place. They implement the CPU-intensive stuff, in a form that a high-level language like Python can make use of. If you look, you see will see where Python is popular in such compute-intensive and data-intensive applications.
1
@keris3920 Consider a basic λ-calculus expression like f = λx.λy.x + y Python accepts a straight transliteration of this: f = lambda x : lambda y : x + y Just to prove it works: add2 = f(2) add3 = f(3) and now the expression “add2(3)” returns 5, while “add3(4)” returns 7. That only works because Python functions are first-class objects, with lexical binding. C++ has never heard of lexical binding, has it?
1
Python Devs: “And this is how you implement the Y-operator from λ-calculus.” C++ Devs: unintelligible, angry swearing
1
That would mean that every class type would have to provide methods implementing this functionality, whereas with the Python way, it only needs to be implemented once, as a built-in function.
1
If it never ends, then it becomes a habit.
1
Using “=” for assignment was a mistake. It was a mistake in Fortran, it was a mistake in C, it’s a mistake in all those languages that have copied C (including Python). Consider also the inconsistency: if “==” is the equality comparison, and negated versions of operators are just supposed to have “!” in front, then why isn’t the inequality comparison “!==”? The Algol language family (including Pascal and its offshoot Ada) invented “:=” for the assignment operator, reserving “=” for equality comparison. This I think makes much more sense. Perhaps walrus in Python was a backdoor way of introducing this usage, at least in part?
1
@TheNewton Just use “:=” for assignment, following the Algol tradition.
1
This feature is implemented entirely at the syntactic level by the compiler. This means it works even for your own custom types where you write your own definitions for e.g. __lt__, __eq__ and the other comparison methods: you just write them as regular two-argument functions, and Python takes care of the rest.
1
Another handy feature of Python’s operators is actually very subtle. So subtle, that I only discovered it by accident one day: the operator precedence differs slightly from C. Which lets you write things like flags & mask != 0 or flags & mask1 == mask2 Any C programmers squirming at that? Because the operator precedence in C requires you to write (flags & mask) != 0 (flags & mask1) == mask2 otherwise they won’t do what you expect! Now, changing the precedence rules in C to remove the need for these parentheses would, in principle, be backward-incompatible; but can anyone come up with actual real-world C code that would break if the rules were changed to be more like Python?
1
Look up POP-11. It has the concept of an operand stack, so assignments go naturally left-to-right. E.g. a, b -> a -> b swaps the values of “a” and “b”.
1
However, note a language inconsistency. While [isinstance(i, int) for i in sample_list] is equivalent to list(isinstance(i, int) for i in sample_list) which computes the same list as l = (isinstance(i, int) for i in sample_list) l = list(l) These are not equivalent to l = (isinstance(i, int) for i in sample_list) l = [l] which returns only a list of a single element, being the generator object. This seems like a deliberate design decision.
1
I have yet to find a use for this myself, so so far I have just been ignoring it. The “«true-part» if «cond» else «false-part»” conditional expression, on the other hand, gets on my nerves. Because Python needs a conditional-expression form, but that is just an abortion. So I came up with my own solution https://ldo17.tumblr.com/post/17544419704/conditional-expressions-in-python .
1
Given the myriad applications of dynamic memory, that must severely limit the kinds of applications you write. Consider that even text strings require dynamic memory, unless you impose arbitrary limits on the lengths of your buffers. Here is a discussion of how to manage dynamic memory: https://github.com/ldo/a_structured_discipline_of_programming
1
@IamusTheFox What else is “delete” for, if not dynamic memory?
1
But do they have zero overhead?
1
Because once you give up on the “zero-overhead” principle, most of C++ just becomes ... pointless.
1
I see C++, Java and C# as being on a spectrum of “semi-dynamic” languages. C++ tries to be static, but secretly it wants to be dynamic (virtual methods, RTTI). Java and C# are only grudgingly dynamic--look at how convoluted Java’s Reflection API is, for example. In all of them, the more dynamic the things you try to do, the more complicated it becomes.
1
2:22 I can’t think of any situation where I would use “with open(...)”. In CPython, the file object will be closed anyway once the last reference to it disappears. For read-only files, this behaviour is fine. For files I am writing to, I want to do an explicit flush or close at the end, for obvious reasons. Either way, a with-construct seems unnecessary or even gets in the way.
1
Can you give a non-contrived example of using it? Because I have yet to find one.
1
@PythonPlusPlus Why should it be? Python alllows one-element tuples precisely for situations like this.
1
@PythonPlusPlus Actually, I notice that you didn’t mention any need for “if” semantics, even though your code has an “if” in it. So which code makes more sense: the one with the spurious “if”, or the one which avoids it?
1
@vogel2499 You don’t really mean that, do you?
1
@PythonPlusPlus Are you saying that loops must iterate at least twice in order to be proper loops?
1
@PythonPlusPlus So you have to decide beforehand how many times the loop is going to loop to decide whether to use a loop or not?
1
Previous
1
Next
...
All