HNHacker News
TopNewBestAskShowJobs

ubernostrum

12,994 karma · joined June 4, 2008

submissionscomments
ubernostrum··on Show HN: Analysis of 2018 Hacker News “Who Is Hiring” Job Posts
Python was already strongly typed long before Python 3.

Python does not have static typing as a built-in part of the language. It has had the ability to annotate arguments and returns of functions/methods since 3.0, a standard-library module containing helpful code to use this for type hints since 3.5, and the ability to annotate variables since 3.6. Annotations are a completely optional feature and no built-in part of Python will check these annotations or analyze code for correctness in advance of execution; there are third-party tools to do this, if you want it.

Also, Python most certainly does compile -- the CPython interpreter is a virtual machine which runs bytecode, and Python source code is compiled to bytecode for that VM. There isn't a requirement to run a completely separate standalone Python compiler ahead-of-time to generate the bytecode (if bytecode isn't available, Python will compile source to bytecode on a per-module basis as those modules are loaded), but that doesn't mean it isn't compiled.

As to "strong" typing:

"Strong" typing is a term that's only vaguely defined, but most commonly refers to whether a language will implicitly coerce/cast values of incompatible types in order to make an operation succeed. Consider this code:

    a = 1
    b = "2"
    c = a + b
In a strongly-typed language this is an error¹. Depending on other aspects of the language, it may be a compile-time error or it may be a runtime error, but the important thing is that the third line of that sample will never successfully execute. In a weakly-typed language, the third line could execute, and would assign a value of either 3 (if the string is coerced to number) or "12" (if the number is coerced to string). And in fact, in Python the third line above raises a runtime TypeError, since str and int are incompatible types for the "+" operator to work with.

Static typing refers to a situation where both names and values have types, and where all attempts at binding must involve names and values of compatible types. For example, in Java:

    int a = 3;
The name "a" is declared to be of type int, and the value 3 is of type int, so the binding of the value to the name succeeds. Attempting to bind a non-int value to the name "a" would fail. In a dynamically-typed language, only values have types, and the type of a value does not restrict which names it can be bound to.

You can remember this easily by considering why the name "static" is used: it's because you can perform checks of name/value types and bindings statically, without needing to run the code to determine types. In some languages (like Java) this is accomplished by requiring all names to be explicitly annotated with their types; in others the types will usually be inferred automatically from usage, with the option to annotate when desired or to resolve ambiguity.

--

¹ Yes, yes, I know someone on HN is going to suffer a terrible career-ending injury from how fast his knee jerked at that and possibly from breaking his wrists in his rush to post "Well actually there may be a type defined somewhere that's a union of string and number, so how dare you say that's an error when you don't know if someone might be using such a type!" My advice is not to be the type of person who suffers severe injuries due to such an obsessive need to nit-pick, because reasonable/charitable readers will correctly understand the example with no difficulty.

ubernostrum··on T.M. Landry and the Myth of Meritocracy in Education
It's difficult to say for certain that the Ivies are actually that high in terms of academic quality. There's a history of people literally tweaking evaluation and ranking criteria until they get the Ivies to come out at the top. For example, US New and World Report got rid of a statistician whose algorithm didn't put the Ivies at the top of their rankings, and replaced with someone who would "fix" that:

https://washingtonmonthly.com/2000/09/01/playing-with-number...

ubernostrum··on Clearing Up a Few Things About Facebook’s Partners
Facebook appears to have designed their system in such a way that permissions were not granular enough to do things like "Spotify can only post certain types of messages". Instead it had to be "Spotify has full read/write access to all private messages".

Given Facebook's history it's hard to believe that the lack of granularity, and resulting incentivizing of users to grant as much access to personal data as possible, was an accidental oversight.

ubernostrum··on Python gets a new governance model
This was borrowed straight from Django's process; our technical board gets re-elected every release cycle.

It's a pretty low-traffic and low-turnover group in Django. I've done it four releases in a row, for example. When there's only one feature release in most years, it's not an issue at all to do a quick call for volunteers. In Django's case, often there's not a real need for an "election" since you only get as many volunteers as there are spots on the technical board.

ubernostrum··on Python gets a new governance model
The new Python model is pretty similar to what Django has been using for years (and even admits that it copy/pasted significant chunks of text from our model). I didn't realize how grim things were!

I've served on Django's technical board -- its equivalent of the new Python "steering council" -- for several years. The technical board has the following responsibilities:

* Act as a final tiebreaker for any decision that the dev mailing list can't manage to make through normal discussion

* Review major proposals for changing Django or Django's processes (DEPs, our equivalent of Python's PEPs), with the ability to veto

* Review proposals to add new Django committers, with the ability to veto

The first category has never, as far as I can tell, come up, and for the other two the technical board has never vetoed a committer or a DEP. There also aren't many of them -- 24 in a bit over four years.

I'm trying to push through a significant change to how Django works, but it wouldn't do away with the technical board; instead it acknowledges that the in-practice way Django runs -- discussion on the dev mailing list, open to everyone, with a couple people whose job is to merge PRs -- is working well enough that we no longer need to give special privileges to a large group of committers.

ubernostrum··on Reasons Python Sucks
There is one other thing that could break, but it would be a weird one. Which is hard to explain in prose, so here's some example code:

    class SomeMetaClass:
        def __new__(name, bases, attrs):
            pass

    class SomeClass(metaclass=SomeMetaClass):
        pass
Now suppose that SomeClass needs to use the typing module's mechanism for indicating a generic, so you could do an annotation like "SomeClass[SomeOtherType]". So you'd want to have SomeClass be a subclass of, typing.Generic[T]. That would, in Python 3 prior to 3.7, raise a TypeError due to metaclass conflict -- the generics in the typing module had their own base metaclasses. So you actually had to define an intermediate class to resolve the metaclass conflict, and do like so:

    class IntermediateMeta(SomeMetaClass, typing.GenericMeta):
        pass

    class SomeClass(metaclass=IntermediateMeta):
        pass
(this was weird and rare and GenericMeta was never documented)

Python 3.7 implemented PEP 560, which introduced the __class_getitem__ hook for implementing the behavior GenericMeta used to handle, and doing away with the need for the typing generics to use GenericMeta as their metaclass. So GenericMeta exists in Python 3.5 and 3.6, but no longer exists in Python 3.7, and anything which tries to reference it will break.

ubernostrum··on Reasons Python Sucks
Mangling of double-underscore names isn't there to provide access control like in Java or C++.

Mangling of double-underscore names is explicitly documented as existing "to avoid name clashes of names with names defined by subclasses". The use case there is a parent class defines a method called, say, "foo". Other methods of the parent call self.foo(). Then a subclass overrides foo() but changes the signature (say, by adding a new non-optional argument), and doesn't override the other methods that call self.foo(). Without name mangling or something like it, this breaks. If the parent class either names the method "__foo" or aliases a copy of the parent class' implementation to "__foo", and calls self.__foo(), name mangling ensures those calls will find the right (as in, compatible) implementation of the method based on where the call came from.

That's it. That's the one and only use case for invoking name mangling in Python, and it's a thing that generally you shouldn't be doing anyway.

Name mangling also isn't invoked for leading + trailing double underscore -- a "__foo__()" method would not get mangled.

ubernostrum··on Reasons Python Sucks
probably needs written in C because built-in types are closed

"Everything is an object" does not necessarily imply "all objects are always infinitely monkeypatchable at all times". It also doesn't necessarily imply "you can change how the parser interprets literals".

You're also going to be really mad when you learn about __init_subclass__ and the fact that Python lets you write a class that can't be subclassed!

ubernostrum··on Reasons Python Sucks
No easy way to remove the package.

"pip uninstall" has been around as long as pip has.

Theoretically, it can upgrade the version but the user mostly don't.

In practice, people deploy to a virtualenv that gets recreated on each deployment, and tend to treat a virtualenv as an ephemeral thing.

ubernostrum··on Reasons Python Sucks
Easy for simple code for middle schoolers. For grownups with large codebases to develop and maintain, it's not optimal.

Yes, like the tiny puny baby middle-school children who built microscopic useless toy "programs" (not even worthy of the name) at Instagram, YouTube, Dropbox...

What I really, really hate is the lack of static typechecking.

Then don't use dynamically-typed languages. Not everyone shares your tastes, nor do they have to.

And just as bad the fact it is impossible to encapsulate code.

The more you write here, the more I think C# is a great language for you. And I don't dislike C#! But you want a nice statically-typed object-oriented language with data hiding. C# is an example of one. Python is not.

And then the GIL!!

I've written at length about how the existence of the GIL is the result of tradeoffs that seemed perfectly reasonable at the time (keeping in mind that Python is older than Java, and I suspect older than the average HN commenter). With 20/20 hindsight would a different approach have been better? Sure, but if they'd had the ability to see the future in enough detail, the folks who chose those tradeoffs probably would have bought lottery tickets instead of building Python.

ubernostrum··on Reasons Python Sucks
I regularly wish python required some sort type indication for function parameters

As others pointed out, Python has optional type annotations and has had them since 3.0. They're static-only (you don't get runtime type checking from them), though, and getting what you want out of them will effectively require every single function, method and variable in not just your codebase but in every third-party dependency and all of their dependencies to be annotated.

Also, annotating "complex objects" tends to be an unreadable mess. If you have lots of functions which take complex objects as arguments, rather than a more clear list of parameters, that's probably not going to be solved by type annotations; it will be solved by rewriting the functions. In other words, you probably will not be helped by:

    def foo(o: HugeLongComplexTypeDefinition) -> OtherHugeLongComplexTypeDefinition
But you would be helped by:

    def foo(widget: Widget, operation: WidgetOperation, tolerance: float) -> Widget
ubernostrum··on Stop Learning Frameworks
I've read The Pragmatic Programmer on a 10 hour flight and I fell asleep 2 or 3 times, because it was freaking boring.

Either you already knew that the things it recommended were good ideas and were doing them, or you haven't yet learned why the things it recommended were good ideas. I know "soft skills" is a euphemism for a bunch of stuff that I'd rather not unpack here, but personally I do think learning good practices around how to write maintainable, testable code are actually, y'know, important and useful, even if they get communicated with icky horrible soft words instead of burly awesome hard math symbols.

This means algorithms and math.

If you say so. But the niche for heroic god-tier 100000000000000000000x rockstar wizard ninja gurus who roll their eyes at tiny puny baby-child beginners while channeling the heartbeat of the universe to derive the Perfect Algorithm™ is... pretty small, and getting smaller ever year. Working programmers don't -- or maybe shouldn't, but oops, that's a "soft skill"! -- actually re-invent all of CS from first principles on a daily basis. And there's really no level of programming you can run to anymore to escape. It's frameworks and libraries and gluing stuff together all the way down, even into the "bare" metal (which isn't so bare anymore, and is a rich programming environment in its own right).

I mean, maybe you work someplace that routinely has to invent entire new fields of theoretical math just to describe the stuff you're building. But I've worked at a household-name place, and known plenty of other people who worked for other household-name places, and in my experience and their anecdotes that kind of stuff is vanishingly rare.

Also, I'd be willing to bet almost anything that you didn't start out as a programmer by reading Turing's "On Computable Numbers" and going from there. You probably started out with an already-built, friendly programming environment in which you could slap things together to see what happened, and only later -- possibly years later -- started to dive into all these "fundamentals" that you now insist everyone learn up-front instead.

ubernostrum··on Why we should care about the Nate Silver vs. Nassim Taleb Twitter war
I've always treated 538's forecasts as meaning nothing more or less than "We have a model, we fed the current data into it and ran N simulations of the event, and in X% of those simulations, this was the result". Which, as I understand it, is literally how they're generated.

Any discussion of the accuracy of the model (which should be the only thing that admits debate) has to be retrospective. Just saying "well the forecasts changed" doesn't inherently discredit the model, especially because things like elections turn out to be highly sensitive to tiny variations (even something as simple as a rainy election day in a few key precincts can completely flip an outcome).

ubernostrum··on Can Foundational Physics Be Saved?
The counterpoint is that if we were more eager to ditch theories as soon as they fail to explain absolutely everything in the universe, we'd have tossed Newton's laws in the early 1800s because they didn't accurately predict the orbit of Uranus.

(turned out they did, but nobody at the time knew to account for perturbations caused by the as-yet-undiscovered Neptune)

And depending on how far you want to take this, the neutrino probably would've been dismissed, too, before eventually being detected.

ubernostrum··on Fun with Unicode in Swift
The Perl doc mostly refers back to suggestions from UAX#31, along with specific notes from UTR#36 and UTS#39.

The suggestion it cares most about from UAX#31 is to restrict to scripts that actually are in use (i.e., don't let people name variables using Linear B characters). If you want to layer that on top of a base pool of identifier characters taken from XID_Start/XID_Continue, you can, and that's not the same as "invent your own base pool of identifier characters".

The big thing you get from reading UTR#36 and UTS#39 is learning how to detect or prevent homoglyph attacks (like people registering "paypal.com" but with Cyrillic "a").

And UTS#39 takes the ideas from UAX#31 all the way and gives you an example of defining profiles on top of the base set of identifier characters to deal with specific issues. It's OK to do that!

Finally, the things that, in a programming language's allowed identifier syntax, would be prevented by going to a more restrictive profile on top of XID_Start/XID_Continue, are vanishingly rare and tend to be exploitable only if you're already completely owned. For example, if someone can slip a mixed-script confusable identifier into your source, they can already slip things into your source; you're owned in so many ways at that point that it starts seeming silly to focus with laser intensity on just this one issue. Which means that if you just want an easy-ish to implement baseline recommendation, XID_Start/XID_Continue isn't that bad.

ubernostrum··on Fun with Unicode in Swift
Not quite.

Reject any mixed-script confusable (and for certain types of inputs, like email addresses, validate sub-components separately -- someone might get to choose their local-part but not their domain).

For strings which aren't mixed-script confusable, if you need to use them as identifiers and perform comparisons with them, normalize to NFKC and case fold. Doing so will eliminate any ligatures, stylistic variants, composed versus decomposed forms, or other things that people use to call Unicode "weird".

ubernostrum··on Fun with Unicode in Swift
The rejection of XID_Start/XID_Continue linked from the Rust issue is not, as far as I can tell, due to "weird" issues -- it's because the sets of characters with those properties can change over time as Unicode adds more characters.

Other languages tend to solve this by stating that version X of the language uses identifiers having those properties in version Y of the Unicode database. This is a problem for C and C++ because of how infrequently those languages update their standards and how glacially slowly implementations adopt new versions of the standards. It's less of a problem for languages like Rust where the language spec and standard toolchain evolve on a much faster (at least one update per year) cadence.

The tweet you link complains about U+2800. That character is not in XID_Start or XID_Continue.

http://www.unicode.org/Public/11.0.0/ucd/DerivedCoreProperti...

So a language adopting XID_Start/XID_Continue would not allow U+2800 in an identifier. And in fact if I try it in Python I get "SyntaxError: invalid character in identifier".

ubernostrum··on Fun with Unicode in Swift
I think it's useful, if you feel it's a burden to have to interoperate with a codebase using non-ASCII identifiers, to consider how literally every person in the world whose native language is non-ASCII must have felt being forced to use it for programming.

Let people who have to interoperate with multilingual colleagues settle on conventions for doing so. Let people who don't use their own language already.

ubernostrum··on Fun with Unicode in Swift
If you take the position that every codebase everywhere must be available to and understood by every programmer everywhere, sure, you have to settle on a common language. Luckily, I don't think anybody takes that position, or at least takes it seriously.

But there are plenty of monolingual dev teams out there whose shared language isn't English and isn't written in ASCII. Why should they be forced to write code in English if nobody who works with it is an English speaker?

I already regularly see people post questions to Stack Overflow and mailing lists and IRC where names of classes and functions and variables are ASCII but not English (i.e., someone writes a class called "Utilisateur", not "User"). Why not let them just use their language fully?

ubernostrum··on Fun with Unicode in Swift
Unicode in identifiers is an exceptionally bad idea

Unicode identifiers can be perfectly well-defined, and many languages have them. The general idea is an identifier can start with any character that has derived property XID_Start, and the remainder can be any characters that have derived property XID_Continue.

different characters looking identical, or the same character encoded in different ways

Follow the recommendation of UAX #31 and normalize identifiers to NFKC prior to comparing them. For example, the ligature variants in the article should not -- if recommendations are followed -- be different identifiers. Here's some Python (3):

    >>> import unicodedata
    >>> raw = ['vpnTrafficPort', 'vpnTrafficPort', 'vpnTrafficPort', 'vpnTrafficPort']
    >>> normalized = set(unicodedata.normalize('NFKC', s) for s in raw)
    >>> normalized
    {'vpnTrafficPort'}
So there wouldn't be a "surprise" lurking in Python -- all four strings are legal identifiers, but all four of them are also the same identifier (because Python applies normalization).

The real difficulty with Unicode identifiers is in places where you really can't avoid Unicode: user inputs. Those who don't read Unicode technical reports are doomed to suffer the moment they build, say, a user-account system that comes into contact with the real world.

When you allow Unicode identifiers, you don't "internationalize" your code

No, you let other people localize their code. We (the tech world) spent decades making everyone else learn English as a prerequisite to learning a programming language. Now we have the ability to lessen that burden and let the non-ASCII world (which does in fact include English!) spend less time learning English and more time writing code. We probably should do that, even if it seems icky to you.

ubernostrum··on Why Use F#?
My editor understands when to indent in Python, and often when to dedent. When it doesn't know to dedent, I just hit Backspace on the next line to close the indented block.

I understand it's a matter of taste, but I don't understand why people insist on repeating themselves -- you're already going to have something indent your code for readability, why not have that just be what the language uses, too?

That said, you should know that in Python, at least, there is famous first-class support for the brace styles of many other languages, invoked by the brace operator "#". For example, if you want C-style braces you can simply write like so, using the brace operator to tell Python what you're doing:

    def hello(): # {
        print("Hello, world!")
    # }
And Python will automatically understand it correctly!

A more complex example uses Ruby-style "end" and conditionals:

    def odd_or_even(num):
        if num % 2:
            return "Odd"
        else:
            return "Even"
        # end
    # end
Python's advanced brace-style parsing AI will correctly handle this. You can even mix and match brace styles within a single codebase, or even a single file, for times when your team just can't agree on one approach.
ubernostrum··on Type hints cheat sheet (Python 3)
The exact error you're going to get in a modern Python is:

    TypeError: 'type' object is not subscriptable
That's because "list" refers to the class object, which is not an instance of list; it's an instance of type. Implementing __getitem__ on list (which is already implemented!) will not help. Try it yourself:

    class MyClass:
        def __getitem__(self, key):
            return f"You asked for {key}"
Now try "MyClass[int]". You'll get the same error: "TypeError: 'type' object is not subscriptable". Class objects in Python are instances of type, so __getitem__ would have to be implemented on type in order to make this work. Which would in turn make it work on any type in Python, not just those which are supposed to represent collections/mappings.

The typing module's solution of sentinel objects to stand in for collection/mapping types, supporting subscripting for annotating the types of contents, is probably a better solution.

ubernostrum··on Type hints cheat sheet (Python 3)
Suppose you want to indicate that a particular variable is a list of int. You might write "list[int]" to indicate that. But try that in a Python interpreter and you'll get an error -- "list[int]" attempts to subscript the list class object, which doesn't work.

So typing.List exists to be a subscriptable object you can use when annotating, and "typing.List[int]" works. Same for the other names.

ubernostrum··on Type hints cheat sheet (Python 3)
Is there an actual dummy class called `typing.Any` that will magically pass a type comparison against any other Python object?

There is an object called "typing.Any". It's a singleton, immutable, un-subclassable sentinel object for static type checking tools to recognize and handle. Runtime type checkers cannot work with it; it actually overrides both the __instancecheck__ and the __subclasscheck__ special methods to raise exceptions and forbid attempts to use runtime isinstance() or issubclass() checks against Any.

ubernostrum··on Madoff’s Victims Are Close to Getting Their $19B Back
The analogy to stolen goods is useful.

Generally, if you receive stolen goods, there are two possibilities: you knew they were stolen (read: a prosecutor can convince a jury you knew), in which case you lose the goods and get prosecuted. Or you didn't know they were stolen (read: prosecutors can't convince a jury you knew), in which case you merely lose the goods.

This may seem unfair from the perspective of the unknowing recipient of stolen goods, but letting them keep the goods is equally unfair from the perspective of the original victim, and would feel like the law giving its blessing to the theft (it would also encourage schemes to knowingly but with plausible deniability receive stolen goods). So there's no solution that is guaranteed to appear fair from all perspectives. But the law generally sides with returning the goods to the original owner, effectively undoing the original theft.

In this case, the "investors" who are being targeted by the suits are also getting to keep their own original capital; they're just being required to hand back the ill-gotten gains. So the remedy is effectively undoing the Ponzi scheme.

ubernostrum··on South Korean law to punish boosters passes in the National Assembly
Given that playing video games competitively for a living is possible through large prize pools in quite a few games, and that South Korea has historically been a powerhouse of gaming, it seems not at all surprising to me that they'd treat this as fraud and try to crack down on it.

There are plenty of other types of competitions where fraud carries legal penalties, after all.

ubernostrum··on O2 'to seek millions' in damages over data outage
As someone who used to speak decent French, you will never convince me that the language is rational with respect to numbers. The sometimes-decimal/sometimes-vigesimal thing still makes my head spin all these years later when I hear numbers being spoken in French.
ubernostrum··on O2 'to seek millions' in damages over data outage
One would think that a metric country would adopt "k"/kilo as the indicator for thousands and "m"/mega for millions.

Still I suppose it's better than sussing out whether someone is British and using "long" billions.

(in most of the world, "billion" = 10 to the 9th power; in older British usage still sometime seen, "billion" = 10 to the 12th power, and 10^9 is "thousand million")

ubernostrum··on Tesla Autopilot and Euro NCAP
Airlines have also had to do special training courses to teach pilots not to get over-reliant on automation. Tesla's "autopilot" seems to fall in that category of being just enough automation that it gets people complacent, but not enough to actually let them safely be complacent.
ubernostrum··on The Rise of Microsoft Visual Studio Code
As someone else who's run a lot of interviews including tech exercises (as much as I hate the typical way they're done, I haven't been able to eliminate them everywhere I've worked), I have the same experience as the parent commenter. Yes, even with "good" statically-typed languages like $YOUR_FAVORITE_LANG_HERE.

Candidates using those languages can often sketch out the right algorithm and the structure of what the program would look like, but under time pressure have trouble producing something that actually will compile and run properly (and as much as I want "showed they got the right algorithm and how to do it" to be a pass, it isn't always). The "executable pseudocode" nature of the popular dynamic languages is a big advantage there.

It's definitely even worse for C#/Java style languages (though C# is better than it used to be), because of all the heavyweight design pattern stuff you need to implement to do things that are just natural idioms in the dynamic languages. But it's something I've seen happen in a broad range of static languages.

← PreviousPage 2 of 34Next →