[HN Gopher] Maybe We Can Have Nice Things
___________________________________________________________________
Maybe We Can Have Nice Things
Author : ChrisSD
Score : 64 points
Date : 2021-02-17 17:12 UTC (2 days ago)
(HTM) web link (noncombatant.org)
(TXT) w3m dump (noncombatant.org)
| pessimizer wrote:
| > However, for all of NPM's problems, at least it is a package
| management system at all! It's easy to pick on NPM (or
| predecessors like CPAN, or CTAN, or...), but even at its worst
| it's a huge improvement over manually managing dependencies (such
| as by manually vendoring them into your source tree, or just
| telling the user to install such-and-such libraries before
| attempting to compile).
|
| Isn't the labor-intensive nature of manually wrangling all of
| these resources a constraint that pushes people to minimize
| version conflicts and micro-dependencies? The reason that you see
| these problems in NPM (and other version control systems) is
| because the automation _removes_ a constraint.
| cwp wrote:
| Yeah, good point. The reason NPM can have packages like left-
| pad is that it works so well. It's easy to publish a package,
| it's easy to find one, it's easy to install and use a package.
| So sure, why NOT make a package for one function that you use
| all over the place?
|
| There's a downside to all this, but ultimately it's to NPM's
| credit: the tools are so easy to use that people... use them.
| brundolf wrote:
| I feel the need to mention, whenever leftpad comes up, that
| it's impossible for that incident to ever happen again.
| Packages can no longer be unpublished after a brief window
| (48 hours I think?), so if you lock to specific patch numbers
| your dependencies are effectively immutable
| NetOpWibby wrote:
| I wonder if something like supply-chain exists for npm, looks
| super useful.
| mtalantikite wrote:
| Cargo from Rust and go fmt from golang have been some of my
| favorite things these past few years. Cargo isn't perfect, as the
| author points out, but wow is it great to have it as a major part
| of the language's ecosystem.
|
| I recently got access to GPT-3 and was playing around with it,
| which meant breaking out Python for the first time in a while,
| and I just don't understand how anyone deals with it. Poetry
| seems much better than what I remember Python ever having, but
| it's not official of course and not everyone uses it. I somehow
| was hitting dependency issues with packages stuck in Python 2 and
| I couldn't believe that's _still_ happening -- it's been over a
| decade now. Even ran into some very minor Black vs PEP 8 things.
| Somehow every time I touch Python I find myself fighting the
| tooling, which may just be my ignorance or bad luck.
|
| Very thankful for Cargo and go fmt so I can just get on with
| things!
|
| (And also the author is right, the Rust community is super
| welcoming. Thanks for that as well!)
| cwp wrote:
| It's not your imagination. Python tooling is awful.
|
| If I may be forgiven a bit of preaching, I'll point out that
| the fundamental problem with the Python ecosystem is that
| package definitions are executable python code. This means they
| have their _own_ dependencies, and are subject to all the
| pitfalls of general purpose programs - the halting problem,
| non-determinism etc. The Python community keeps trying to fix
| this by writing a better installer, and it 's never going to
| work.
|
| NPM and Cargo, with their declarative package definitions, are
| built on a far more stable base!
| rectang wrote:
| Whatever Perl's other issues, through the introduction of
| `META.json` CPAN successfully augmented a system designed for
| executable install scripts like `Makefile.PL` with a
| declarative package metadata mechanism. Why can't Python do
| the same?
| rst wrote:
| Not sure I agree with this diagnosis -- Ruby gemspecs (for
| components) and Gemfiles (for dependency lists) are both
| executable Ruby code, but packaging troubles at the
| Pythonesque level are rare.
|
| The trouble I've had with Python packaging had a lot less to
| do with the specs being executable code than with there being
| tools with overlapping use cases which interpret them in
| different ways, none of which seems to cover all use cases,
| and whose documentation of what they expect in package specs
| is sometimes in conflict. If the specs turned to JSON-with-
| comments tomorrow, those problems wouldn't go away.
| neolog wrote:
| http://python-poetry.org/ solves the problem by providing
| declarative package definitions.
| dralley wrote:
| Python packaging tooling and infrastructure is exactly like
| this: https://xkcd.com/2347/
|
| Everybody uses it, but the work of maintaining it is
| thankless and doesn't receive nearly as much attention as you
| would expect relative to the popularity of the language.
|
| The unfortunate thing is that there's only a very small
| number of people actively maintaining, and they have so
| little time available that it's nearly impossible even to
| contribute something substantial.
|
| I bore witness to an attempt by my colleagues to replace the
| legacy XML-RPC APIs (which have been publicly declared as
| deprecated for years with no replacement even today) which
| completely fell through because the maintainers didn't want
| to (or have time to) provide any feedback whatsoever. It was
| basically requested that a 100% implementation with 100% test
| coverage be provided before they would even spend the time to
| _evaluate the API design concept_ and give feedback.
| AtlasBarfed wrote:
| "A key innovation of C++ was to introduce RAII, which essentially
| 'piggybacks' on the value of the stack and enriches it with a lot
| more power."
|
| I haven't written C++ in two decades, but it was my impression
| that heap allocated resources are not on the stack.
|
| The major problem with C++ isn't resources can be used used after
| freed, it's that they are never freed if you don't clean up when
| your RAII is popped off the stack via destructor or other "event
| handler methods".
|
| Isn't RAII more of a pattern implemented atop the core
| constructor/destructor? It's kind of a stretch to call it a
| fundamental feature of C++ like GC is to java/jvm.
|
| Has valgrind "solved" memory leaks as a primary concern/danger in
| C++?
| bluGill wrote:
| You should look into modern c++ - at least C++11. While it is
| possible to write the code with all the problems you state,
| C++11 adds some neat features that mean in practice you rarely
| do. Sure I can put something on the heap and forget to free it
| - but in practice I don't put anything on the heap without
| first wrapping it in something on the stack so that when the
| thing on the stack goes away my thing on the heap does too.
| This can get really complex fast to deal with edge cases, but
| most of the time the complexity is hidden and so doing the
| right thing that always works is just as easy as putting
| something on the heap that I have to remember to free latter.
|
| Most people use address sanitizer not valgrind for the few
| times they have a memory leak. In general though the problem is
| solved not by tools but by using the modern C++ features.
| Valgrind is really only useful when you need to deal with C
| interfaces. (note interfaces, the code on either side need not
| be written C)
| RcouF1uZ4gsC wrote:
| RAII is a core fundamental feature of C++ and I would argue
| that constructors and destructors are the implementation.
|
| With RAII (using vector, string, unique_ptr, etc), memory leaks
| are pretty much a solved problem in modern c++. The biggest
| memory danger in C++, in my opinion, is dangling references
| where you have a reference to an object (either on the stack or
| heap) that has been destructed.
| hawski wrote:
| What's a fundamental feature for C++ then, if not RAII?
|
| GC may not be the fundamental feature of Java the language, but
| it is certainly a fundamental feature of JVM.
| ChrisSD wrote:
| The idea in RAII is you create a type that's solely responsible
| for acquiring the resource and freeing it (and little else).
| This idea is indeed fundamental to modern C++ design. For
| example, smart pointers.
|
| When created, the pointer lives on the stack. The resource it
| points to lives elsewhere but that's no concern to RAII. When
| the stack variable goes out of scope the resource will
| automatically be freed (via the destructor)
|
| One place where this can break down in C++ is in copy and
| moves. The acquire/release works simply enough using
| constructors/destructors but correctly handling copies and
| moves has turned out to be harder to get right. And when you
| add in other objects that may refer to the resource object...
| well things can quickly become even harder to handle unless
| you're very careful.
| romaniv wrote:
| _> Programming languages advance by introducing new constraints._
|
| Among other things.
|
| _> throw is a little bit too goto-y for my taste_
|
| Conceptually, throw is not at all like GOTO. It's not a control
| structure, but a communication tool. Throw interrupts execution
| of logic in a subsystem that encounters abnormal conditions and
| _communicates those conditions to the containing system_. The
| second part is the most important one.
|
| _> However, for all of NPM's problems, at least it is a package
| management system at all! It's easy to pick on NPM [...], but
| even at its worst it's a huge improvement over manually managing
| dependencies_
|
| This really depends. In many ways NPM made _introduction_ of new
| dependencies easier, while making handling dependencies over long
| periods of time a much more hairy problem. I don 't like that
| most devs today assume that versioned packages is the only way
| you can do things. Many also don't understand that "dependencies"
| is not a real thing, it's an aggregate label that is applied to a
| set of problems that _happen_ to be solved by package managers.
| Problems like discovery, deprecation and compatibility checking.
| carapace wrote:
| > throw is not at all like GOTO
|
| They are the same thing.
|
| To see it clearly, replace each exception with a label, each
| "try" by a no-op, each "catch" by a label statement, and each
| "throw" by a GOTO statement. try:
| foo() catch BarException baz()
| def foo(): ... throw BarException
| ...
|
| Is like: CALL foo GOTO end
| LABEL bar CALL baz LABEL end
| LABEL foo ... GOTO bar ... RET
|
| Either you have relatively simple exceptions and the equivalent
| GOTOs would also be simple enough to be not "considered
| harmful"; -or- you have complicated exceptions, which is really
| an ad hoc state machine, and you might be better off making
| that explicit rather than hiding it in a tangle of
| try/catch/throw control-flow logic, eh?
| losvedir wrote:
| I had taken for granted that RAII was a good and useful pattern,
| from my dabbling in rust and what I've overheard in C++. So I was
| surprised and interested that Zig rejects that, in favor of a
| `defer` construct somewhat a la Go to free resources. I'm not
| sure I agree, but it shows that "advances" in PL design aren't
| universally agreed as such.
|
| I guess what I'm getting at is I agree with the article that it's
| great that programming languages develop new ideas and
| constructs, but it's not always obvious which ones are "winners".
| How do you even really judge that? The quantity and quality of
| software in the language? Polls of developers?
| bluGill wrote:
| There isn't a good answer. RAII is a great thing that I use all
| the time. However it requires deterministic destruction which
| in turn means some form of reference counting garbage
| collection. Garbage collection research has found non-reference
| counting garbage collection has a lot of advantages. So as a
| language designer you need to choose, better garbage collection
| at the expensive of non-deterministic destruction, or worse
| garbage collection but you get RAII. There isn't a clear
| winner.
|
| For about 80% of all garbage this doesn't matter because it
| turns out the reference count is always one until it goes to
| zero so you don't need to track it, and in turn this means the
| better garbage collection algorithms I mentioned above are not
| better in this case. However this rule of thumb comes from C++
| where training (based on real performance needs of the type of
| code you might write in C++) keeps people from doing the types
| of operations that would increment the reference count. Which
| is to say even if Java could figure which cases can use this
| rule (this appears like variant of the halting problem to me),
| they would probably discover that the number there is enough
| less as to not make it worth adding.
|
| Worse, in C++ there is a tiny number of data structures with
| circular references that you cannot use reference counting to
| deal with. Thus as a C++ programmer will sometimes have to
| write some other garbage collector for the edge cases, and
| these don't get RAII deterministic destruction.
|
| Note that I didn't state the advantages of better garbage
| collectors. I am not an expert here, so I'm leaving it as an
| exercise to the reader. Just know that there are advantages to
| them that make them a great choice for some problems despite
| losing RAII! If you are designing a language you should
| probably look into this early. (I was going to say a hybrid is
| the worst of both worlds - but maybe I'm wrong so I'll let you
| figure that out)
| tsss wrote:
| There are still people who disagree that the world is round and
| a very very large portion of the populace is religious when
| it's abundantly clear that religion is bullshit. Go is an
| outlier with a huge media machine behind it and it will
| disappear back into the abyss as soon as Google stops pushing
| it with no contributions to programming language research at
| large.
| DonnyV wrote:
| I love when I read about languages and they completely ignore
| .NET and C#. Like it hasn't advanced in leaps and bounds.
| pjmlp wrote:
| And everything that has existed outside Bell Labs and UNIX.
| tptacek wrote:
| The programs Palmer is talking about already exist, and are
| already implemented in C and C++, languages without managed
| runtimes. Rust is interesting here because it is memory safe
| and also doesn't have a managed runtime.
| carapace wrote:
| A programmer's opinions of various technologies is highly
| trajectory-dependent. The problem of uneven distribution of
| lore is exacerbated by two startling factors: we tend to be
| ignorant of the history of our field; and we are fashion-driven
| to a fault. I suspect that's how you get educated intelligent
| people with, um, unusual ideas about things. (E.g. I've worked
| with fellows who did not know who Alan Kay was, or what Prolog
| is.)
|
| In re: Rust, Graydon Hoare gave a talk on the history of
| compilers in which he doesn't mention Prolog.
| https://thenewstack.io/rust-creator-graydon-hoare-recounts-t...
| I suppose he just didn't think it was relevant, but it's
| possible even he is a little ignorant?
|
| I see a ray of sunshine in the form of a nascent and inchoate
| new paradigm that could be called "Categorical Programming",
| Conal Elliott has the scent: http://conal.net/papers/compiling-
| to-categories/ CT provides a mathematical formalism for finding
| the most highly factored forms of various functions/programs,
| enabling a kind of "convergence" of code to its most efficient
| form. But that's a big ol' tangent.
|
| My point is, it's often more informative to try to understand
| the context in which something someone says makes sense, than
| to just decry them as wrong. Oh, and to remind folks to read
| your history!
| ibraheemdev wrote:
| .NET will always be looked at as enterprisey, and old school. I
| agree that it has advanced a lot, but I don't think anything
| will change that perspective.
| MereInterest wrote:
| And Windows-only. I know that Mono has made some good
| strides, but relying on it for the language itself adds a
| much bigger risk factor.
| DonnyV wrote:
| This is exactly the mindset of a lot of developers that
| don't even bother looking at .NET. If you did. You would
| know that .NET is far beyond offering Mono. .NET and Mono
| merged back in 2016 to form .NET Core. Which was supported
| on all major OS platforms and was open sourced. .NET 5 was
| released in 2020 which merges the rest of .NET, including
| WinForms. Now all open sourced. .NET 6 has already been
| announced with a cross platform UI framework. So
| enterprisey and old, it is not.
| ibraheemdev wrote:
| Yup .NET Core being cross-platform and open-source is a
| huge deal, and Blazor looks really cool, but I still
| don't think the way people look at C# is going to change.
| PaulHoule wrote:
| "throw" is a nice thing in my mind and not at all like goto.
|
| Before there was "throw" people wrote C programs with no error
| handling at all, or globals used to pass error conditions, or
| something like "Optional" with no syntactic sugar and 250% more
| coding errors.
|
| Error handling is ultimately a non-local concern (e.g. this
| subroutine failed because somebody cut a fiber in Nebraska.)
| timw4mail wrote:
| Error handling is an everywhere concern. In general,
| recoverable errors are more local, and unrecoverable errors
| should crash/throw.
| PaulHoule wrote:
| "Recoverable" means different things.
|
| Where I work we would rather the app crash than display
| incorrect data -- accuracy is critical to us.
|
| The engine control unit in your car has multiple degraded
| modes it operates in when parts like the oxygen sensor fail
| -- in that business the "show must go on" but so does the
| "check engine" light.
|
| Fly-by-wire airliners like the A320 and B777 also have a
| number of degraded modes that pilots are aware of and there
| is a huge database of experience that proves the concept.
|
| The 737 MAX hack tried to bolt a primitive form of flight
| envelope protection onto the old hydraulic control system but
| didn't consider that the plane would sometimes encounter
| degraded conditions such as one of two AoA vanes failed.
| timw4mail wrote:
| Absolutely, which is one of the reasons good error handling
| is difficult. The context of use for the current code
| determines how errors can be handled.
| XorNot wrote:
| This doesn't feel like it translates into anything actionable
| though.
|
| For example: I've never had a problem with Python's approach
| of defaulting to exception handling because it seems to
| bridge that gap nicely: either you can handle it in your
| local catch block, or you want to send it higher up to see if
| something with hopefully more context knows what to do.
|
| Most error handling where "error's are values" is still
| ultimately doing this exact thing somehow it's just a
| question of with what implementation.
| [deleted]
| jstimpfle wrote:
| Here are a bunch of error-handling strategies that I'm aware of
| (which one is valid depends on the situation).
|
| - Die immediately / assume the error won't happen, but still
| code defensively.
|
| - Throw an exception (in languages that support this). setjmp()
| / longjmp() also falls in this category, although it is hard to
| do correctly.
|
| - Return an error code to the calling function
|
| - Contain the error in a data structure.
|
| The last is a truly object-oriented approach. In larger systems
| this is the one that scales. Its advantage is that it decouples
| the error detection from the handling (temporal decoupling) and
| allows the error to be handled asynchronously. This is a
| property that exceptions don't have.
|
| Exceptions are, in my experience, not nice to use. If you
| _actually_ want to handle errors (i.e. not use them only as a
| glorified die() function) the code gets really ugly - you tend
| to use them like error return values, but with more verbose
| syntax (having two return mechanism is bad since it reduces
| compatibility of code).
|
| I know a situation where exceptions can be useful: when
| interpreting a chunk of code in a sandbox in a synchronous
| fashion - i.e. you call the interpreter function of that
| virtual process, and that process either completes successfully
| or terminates with an exception. The virtual process is then
| cleaned up. There is no possibility to interrupt the
| interpretation and resume some time later.
|
| This is more of a toy setting, though. You don't write complex
| systems like that.
___________________________________________________________________
(page generated 2021-02-19 23:02 UTC)