|
|
Subscribe / Log in / New account

Not coalescing around None-aware

Not coalescing around None-aware

Posted Dec 28, 2022 9:22 UTC (Wed) by tialaramex (subscriber, #21167)
Parent article: Not coalescing around None-aware

I have been convinced for some time that languages without Sum types end up with these workarounds and the price of one such workaround is attractive, but there are a lot of useful Sum types, and it becomes unwieldy to implement a workaround for each.

"None-aware operators" are a workaround for lacking Option / Maybe / the "... | None" ad hoc type.

Exceptions are a workaround for lacking Result / Expect

Languages should bite the bullet and provide Sum types even though that's a lot of work.


to post comments

Not coalescing around None-aware

Posted Dec 28, 2022 21:55 UTC (Wed) by NYKevin (subscriber, #129325) [Link] (5 responses)

Python does support Sum types. In fact, the only (static) type in the language is PyObject*, which is just a Sum over all possible types.

The real problem is that Python is dynamic, and "supporting Sum types" doesn't mean anything in the context of dynamic languages. Well, not unless you want to build some kind of wrapper object that really exists at runtime and can't be monomorphized away. But you don't need language-level support for that, you can Just Do It.

Not coalescing around None-aware

Posted Dec 29, 2022 2:21 UTC (Thu) by tialaramex (subscriber, #21167) [Link] (4 responses)

I guess that yeah, maybe the problem is the dynamism. If I have a Dog type then I can intentionally narrow from Dog | None to just Dog and then write code which knows it's a Dog, not a None. Python doesn't want that, it reminds me of the .NET CLR. Modern CLR languages tend to have explicit nullability, so we can say this is a Dog, and really mean that - it isn't a null Dog, it's definitely a Dog. But the CLR itself doesn't admit this idea, and so all .NET programs must defend against APIs receiving a null even where they explicitly said it wasn't welcome. Your function which takes an integer definitely doesn't get floating point parameters, but your function which takes a (non-null) Dog, can still get fed a null Dog by an older or malevolent program.

Not coalescing around None-aware

Posted Dec 29, 2022 8:20 UTC (Thu) by smurf (subscriber, #17840) [Link] (3 responses)

Python explicitly supports duck-typing. If your non-Dog-derived object barks like a dog, then "dog.bark()" works even if it's a lyrebird. The song-and-dance you need to go through in C++ or Java to achieve that kind of flexibility (among many other common patterns that tend to take one line in Python, a new class in C++, and two source files in Java) is exactly why I'm using Python.

There are ways to declare interfaces for that kind of code; however, if you want to find typing problems statically instead of crashing on them, Python wants you to use a separate checker (like mypy).

Not coalescing around None-aware

Posted Dec 29, 2022 13:12 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

I feel like this greatly depends on the kind of software you're writing. I tend to write "libraries" where reliability is higher on the list than applications which can be more of "we're all good fellas around here *nudge* *wink*" with respect to what you can be given as an argument. Given the kinds of craziness Python ducks can contain, I find it much easier to have that "I only accept types which explicitly claim to support interface X" hurdle. Of course, some languages make it a PITA (C++ and Java require inheritance, but Rust and Haskell can get these tacked on later with `impl Trait`-like blocks), but not every feature comes with every creature either.

Not coalescing around None-aware

Posted Dec 29, 2022 20:42 UTC (Thu) by tialaramex (subscriber, #21167) [Link] (1 responses)

Duck typing is perhaps an appropriate convenience for Python, a language for non-programmers, but what happens is we're polluting a namespace. Having a bark() method does *not* mean you bark "like a dog" but once this unstated assumption takes hold everybody is stuck with it.

This pollution has become pretty bad in C++ where on top of about 100 reserved words like "for" and "reinterpret_cast" and "co_await" there are a vast number of in practice unavailable identifier names which, if you make the mistake of using them, implicitly mark the affected type as having specific properties associated with that word e.g. cbegin() means you're able to provide a constant iterator, size() means you're some container with things inside it. Even though C++ doesn't "Have" duck typing in this respect in practice that's what it does.

Better, I am confident, to be able to state explicitly what you mean, if this Lyre Bird can in fact smurf::animal-noises::Dog::bark that's fine, but it shouldn't be confused with my tialaramex::army::DrillSergeant::bark which is provided neither by Lyre Birds nor Dogs. We need to be clear what is meant.

core::cmp::Ordering and core::sync::atomic::Ordering are both really, really important, but in their own context. Just because my sort method needs an Ordering and your spinlock code has an Ordering doesn't mean they're concerned with the same thing. If the two are in adjacent code, that code needs to spell out what's going on. In unrelated code, the expectation can be stated just once and then context is clear afterwards.

Not coalescing around None-aware

Posted Dec 29, 2022 21:56 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

> Even though C++ doesn't "Have" duck typing in this respect in practice that's what it does.

The mechanism of templating in C++ basically feels like it (since it feels a lot like "structured preprocessor" more than "provides interface"). Concepts should help, but standard library usage remains to be seen.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds