Throwing the ball and watching this little character run was truly a delightful interaction. For whatever part you had in its creation, thank you.
158 karma · joined May 9, 2014
Throwing the ball and watching this little character run was truly a delightful interaction. For whatever part you had in its creation, thank you.
src time node primes.js
78498
node primes.js 1.75s user 0.05s system 102% cpu 1.761 total
src time node --jitless primes.js
78498
node --jitless primes.js 5.06s user 0.04s system 100% cpu 5.088 total
src time python primes.py
78498
python primes.py 4.27s user 0.03s system 100% cpu 4.276 total
src asdf shell python pypy3.9-7.3.9
src time python primes.py
78498
python primes.py 0.91s user 0.07s system 100% cpu 0.970 total
Actually relatively on par with one another.[1] https://en.wikipedia.org/wiki/GADDAG [2] https://www.axioms.me/gaddag/#?page-5
-- This works
alter table announcement_destinations
add constraint announcement_destinations_pk unique nulls not distinct (sender, receiving_group, optional_filter);
but -- Still does not work
alter table announcement_destinations
add constraint announcement_destinations_pk2 primary key (sender, receiving_group, optional_filter);
fails with a message like "ERROR: column "optional_filter" of relation "announcement_destinations" contains null values". Is there a motivation for this distinction?Unfortunately the fractionals method does not work, since there are numbers (in fact, uncountably infinitely many!) irrational numbers which cannot be expressed as fractions, which are nonetheless real numbers (such as the square root of two and pi).
Or add a single type annotations to the method declaring that the parameter satisfies a protocol.
Not exactly a common characteristic for Lisps
Alan Kay argues that bare "data" isn't very meaningful on its own because it leaves the interpretation too open. His view is nicely summarized by the following quote:
> For important negotiations we don't send telegrams, we send ambassadors.
Rich Hickey argues that bare "data" is a fundamental primitive that, while leaving open the possibility of misinterpretation, leaves open the possibility of re-interpretation in multiple contexts. This is the strongest quote I took away from his POV:
> None of the inputs to our sensory systems are accompanied by explanations of their meaning.
Based on your above post, it looks like you're strongly in Alan Kay's camp, which may also explain (in part) your experience struggling with Clojure's approach.
Do you mean libraries like Turbolinks[1] and/or Intercooler[2] here? I'm interested in what libraries you use, and others like these which help "bridge the gap" between traditional and single-page sites.
[1] https://github.com/turbolinks/turbolinks [2] https://intercoolerjs.org/
`keep`: Given a predicate and a collection, filter the collection to retain only items for which predicate evaluates to true.
`discard`: Given a predicate and a collection, filter the collection to discard items for which the predicate evaluates to false.
These are two very reasonable functions that would have the exact same signature, would be appropriate for the same arguments, but have two different behaviors!
What's the proposed fix in this case? Should all clients accessing that field switch to `customer.full_name`? Do you control all of the call-sites? If so, that change is pretty easy to automate in dynamic languages by marking the field as deprecated, adding the new field, and forwarding `customer.last_name` to `customer.full_name`. That way, running systems don't break but you get the new behavior. You can automate logs to track when the deprecated field is accessed and, if necessary, fix call-sites after a reasonable period of monitoring, reducing risk (assuming there's not "once-in-a-century" paths in the code that invoke the call site).
It seems reasonably likely that this is not the desired behavior - you may have external clients, and some callers may be relying on this field to actually return only a last name. In that case, deprecation is still the correct path, I think, since it's unreasonable to expect external clients to immediately fix systems relying on that field being available.
Static typing can tell clients where they need to make changes, but it's not realistic demand that they immediately update every call site, every method depending on that behavior, and every integration with their external dependencies that relied on the interaction between your code and another system. This is why we have (semantic) versioning, deprecation warnings, and support agreements for larger systems. API's should evolve slowly and gracefully over time, not shift suddenly overnight.
I think that's part of the trick, actually. When every component of a system behaves in similar ways, it's easier to extract that behavior into re-usable patterns.
Rather than each component worrying about handling failure and micromanagement, that job is delegated to an another component, a supervisor or orchestrator. Supervision trees, automatic service discovery, and elastic resource managers all come to mind.
What payment systems don't send messages to communicate with the credit card company, or the eCheck service, or Venmo/PayPal/Apple pay? Websites and native apps alike have spinning graphics and loading bars, messages that say "please don't refresh the page while we do this". These systems are fundamentally asynchronous to begin with. By uniformly applying the practices you get consistency, in exchange for a higher low-bar of complexity (which you're likely to exceed anyway).
There's definitely a trade-off, however. They make a huge difference for noisy events (like mouse move, scrolling, dragging, etc), but tend to make debugging much harder in my experience. When things go wrong, the stack traces nest deeply into the event handling systems and code paths no longer resemble the relatively straightforward world of traditional event calls, where a callback handler is invoked directly in response to a single event.
It depends, I think. Abstractions allow users to specify part of a program's behavior independently from others. This is not intended to start a flamewar or pick on Go, but for better or worse Go does not support user defined generic functions. One consequence is that certain kinds of methods are difficult to write in a generic, performant, and type-safe way. If users want performance and type safety, they need multiple implementations of those methods for each desired type. This leads to multiple copies of very similar code (which can evolve independently, lowering consistency) or the use of on of the community-driven code generators (which all have their own differences, again lowering consistency).
Adding generics could largely make all of this inconsistency go away, but as you point out would enable a whole slew of other programming patterns more ways to make a mess.
I prefer to think of abstraction techniques as shifting consistency. Ideally, they provide an obvious way to factor out one piece of a program's behavior, allowing developers to focus on the rest of the behavior independently.