[HN Gopher] Abstraction boundaries are optimization boundaries
       ___________________________________________________________________
        
       Abstraction boundaries are optimization boundaries
        
       Author : delifue
       Score  : 52 points
       Date   : 2025-06-28 14:12 UTC (3 days ago)
        
 (HTM) web link (blog.snork.dev)
 (TXT) w3m dump (blog.snork.dev)
        
       | discarded1023 wrote:
       | The author is right to note that Haskell can optimise across
       | module (abstraction) boundaries. However I remember that in my
       | childhood that Debray [1] did a lot of work on link-time
       | optimisations (late 1980s). And of course there's the classic
       | self work that fed into the JVM [2], and the whole-of-program
       | compilers that are receiving renewed attention now; mlton [3]
       | being a classic of the genre, "supercompiler" being the active
       | area of research AIUI. So at least sometimes abstraction
       | boundaries are transparent to optimisers.
       | 
       | On the other hand the classic data abstraction story
       | (signatures/interfaces for structures/modules) naturally allows
       | for selecting or optimising implementations depending on uses.
       | There was some great work done in the early 2000s on that (see
       | [4]) and I'm sure the state-of-the-art has moved on since [5].
       | 
       | [1] https://dblp.org/pid/d/SKDebray.html
       | 
       | [2] https://en.wikipedia.org/wiki/Self_(programming_language)
       | 
       | [3] http://mlton.org/
       | 
       | [4] https://dblp.org/pid/59/4501.html
       | 
       | [5] https://en.wikipedia.org/wiki/Interprocedural_optimization
        
         | atothayu wrote:
         | hell yea
        
       | mrkeen wrote:
       | They are consistency boundaries too.
       | 
       | > This problem is usually caused by a leaky abstraction; the ORM,
       | or whatever database abstraction you are using, can't anticipate
       | that it would need to send N queries, so it can't automatically
       | optimize this down to a single query.
       | 
       | If you do an if-statement with an ORM before doing an update-
       | statement, the result of the if-statement is already stale before
       | the update occurs. If you skipped the ORM and put your if-
       | statement as a where-clause, it's less of a problem.
       | 
       | > However, this only works since Haskell is declarative / pure;
       | the low-level operational semantics (like evaluation order) are
       | abstracted away from the programmer, and as such are amenable to
       | optimization.
       | 
       | What else is declarative / pure? SQL. Not ORMS.
        
         | sgarland wrote:
         | > What else is declarative / pure? SQL.
         | 
         |  _Thank you._ People so often forget (or don't realize) that
         | their RDBMS is also doing a ton of optimization on their query,
         | and a primary reason it's able to do so in real-time is because
         | SQL is declarative.
        
         | Dwedit wrote:
         | In C#, there is Linq to SQL. Linq to SQL is an ORM. It does SQL
         | code generation, even from user-provided code as long as it is
         | in Linq Expressions form.
         | 
         | With DelegateDecompiler, you can turn native lambdas into Linq
         | Expressions. (You just need to re-wrap the decompiled method
         | body to remove the extra "this" parameter from the lambda).
         | With this, you can write C# code, and it will generate SQL
         | code.
        
       | wavemode wrote:
       | > However, what if we raise the abstraction boundary and make the
       | ORM part of the language? This means that we could formulate
       | rewrite rules for the ORM, allowing it to eg merge the N queries
       | into a single query.
       | 
       | It's correct that abstraction boundaries are optimization
       | boundaries, but I don't think you need to make queries part of
       | the language itself to raise the boundary.
       | 
       | To give a concrete example, take the Django ORM in Python. If you
       | write a function which returns a single database record, then
       | calling that function many times in a loop is naturally going to
       | result in an n+1 query. However, if you instead return a
       | QuerySet, then what you're returning is a lazily-evaluated
       | sequence of records. Then, the caller can make the choice on
       | whether to immediately evaluate the query (when they only need
       | one record) or collect together a bunch of QuerySets and union
       | them into a single query.
       | 
       | In other words we give the caller more control and thus more
       | opportunity to optimize for their use case.
        
         | wat10000 wrote:
         | Abstraction boundaries can be optimization opportunities if you
         | choose the right abstractions. You want to present interfaces
         | that go well with the underlying capabilities. In the case of
         | ORMs, the underlying capabilities include various kinds of set
         | manipulation, so you should present an interface that can
         | filter, union, lazy evaluation, etc.
         | 
         | The key is capabilities rather than implementation. If your
         | data structure is good at iteration and bad at random access,
         | present an abstraction that supports enumeration but not
         | indexing. But don't present an abstraction that hands out Nodes
         | and lets the caller mess around with their Next pointers.
        
       | cogman10 wrote:
       | To answer the OP, no. Your compiler will never do the
       | optimization you want it to do, no matter how high you try and
       | move up the abstraction.
       | 
       | The fundamental issue isn't just that your compiler doesn't
       | understand SQL. The problem is that your compiler doesn't
       | understand how data is or will be stored. It's blind to the
       | current state of the dataset.
       | 
       | For example, maybe it's the case that the data is stored in a
       | hashtable and it's rarely written. In that case, N+1 might
       | actually be the right way to query the data to avoid excessive
       | read locks across the database.
       | 
       | Perhaps the data has 1, 2 or several indexes created against it.
       | Those indexes can change at anytime and have to be consciously
       | made as building them can take a lot of resources.
       | 
       | RDBMS build up a huge amount of statistics for optimizations
       | purposes. That's all information you'd have to have the compiler
       | JIT into the application to get similar performance or to have a
       | good feeling for how to do the optimization.
        
       | joshdata wrote:
       | Is the goal to make good ORM queries easier or to prevent bad
       | queries? It's not clear there's really a compiler solution to the
       | latter. If you're inside a loop in which a database cursor is in
       | scope, then further database queries are prohibited? It's hard to
       | see how that could be enforced other than something like What
       | Color Is Your Function
       | (https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...)
       | with some functions marked as making queries and others as not.
       | 
       | To solve this, maybe instead best practice would be to ensure the
       | database connection is not in a global variable and must be
       | passed down. That would make it more obvious when a database is
       | improperly used within a loop.
       | 
       | The same problem exists for any expensive operation within a loop
       | (say, a database query while parsing the results of an API call,
       | or vice versa).
        
       | nyrikki wrote:
       | IMHO the ORM was an unfortunate choice for trying to develop a
       | generalization about abstractions.
       | 
       | SQL's declarative model has an impedance mismatch with imperative
       | programming, ORMs attempt to deal with that mismatch.
       | 
       | SQL hides complexity but Codd's goals when developing the
       | relational model was to allow non programmers to access data.
       | 
       | The design decisions and tradeoff analysis was massively
       | different than just an abstraction targeting developers.
       | 
       | There are many different persistence models that have vastly
       | different tradeoffs, costs and benefits.
       | 
       | Balancing integration and disintegration drivers are complex and
       | can impact optimization in many ways.
        
         | 9rx wrote:
         | _> ORMs attempt to deal with that mismatch._
         | 
         | Technically ORMs attempt to deal with the mismatch between
         | relations[1] and the rich data structures (objects) general
         | purpose programming languages normally allow expression of.
         | Hence the literal name: Object-Relation Mapping. That SQL, the
         | language, is declarative is immaterial.
         | 
         |  _> but Codd 's goals when developing the relational model was
         | to allow non programmers to access data._
         | 
         | That is unlikely. He was staunchly opposed to database vendors
         | adding "veneer" to make use more friendly and considered SQL an
         | abomination. Codd was dead set on mathematical purity, which
         | is, I'd argue, also why his vision ultimately failed in
         | practice as actual relational databases are too hard to
         | understand for those not well versed in the math.
         | 
         | [1] Technically tables, since we're talking about SQL, which
         | isn't relational. But the mapping idea is the same either way.
        
           | nyrikki wrote:
           | The 'relation' in the relational model is the tables,
           | specific named columns and tuples, with specific abstracts
           | [0]
           | 
           | The relation is the table, normalization, foreign keys,
           | candidate keys etc are all extensions to that base model for
           | Codd.
           | 
           | Some of the impedance mismatch is due to that, and not just
           | the declarative nature or extensions
           | 
           | Specifically I think the Alice book covers how with a
           | candidate key + the remaining tuples in the row form the row
           | but only the candidate key has an identity, the rest of the
           | row is a substring.
           | 
           | Some quotes from the link, but searching for 'user' will hit
           | what I think justifies my interpretation.
           | 
           | > Future users of large data banks must be protected from
           | having to know how the data is organized in the machine (the
           | internal representation).
           | 
           | > To sum up, it is proposed that most users should interact
           | with a relational model of the data consisting of a
           | collection of time-varying relationships (rather than
           | relations). Each user need not know more about any
           | relationship than its name together with the names of its
           | domains (role qualified whenever necessary): Even this
           | information might be offered in menu style by the system
           | (subject to security and privacy constraints) upon request by
           | the user.
           | 
           | [0] https://www.seas.upenn.edu/~zives/03f/cis550/codd.pdf
        
             | 9rx wrote:
             | _> The  'relation' in the relational model is the tables_
             | 
             | No. A table is a _list /multiset_ of tuples, while a
             | relation is a _set_ of tuples. If you squint hard enough
             | they might look similar, but they are not the same. The
             | relational model has no concept of tables.
             | 
             |  _> Some of the impedance mismatch is due to that_
             | 
             | ORM doesn't really have an impedance mismatch in and of
             | itself. It is just a data transformation.
             | 
             | The impedance mismatch that is oft spoken of in association
             | with ORM revolves around the N+1 problem. This is where you
             | get some bizarreness that has to lean on hacks to overcome
             | the real-world constraints that the mathematical model
             | doesn't account for. If you are using something like SQLite
             | that isn't so much of a problem in practice, of course.
        
               | nyrikki wrote:
               | In first order predicate logic with an n-ary relation,
               | attributes are columns and tuples are rows aka a table
               | and what Codd used to justify it.
               | 
               | The typical normalization let's say in a star schema is
               | viewable as a least fixed point. FO+LFP=P
               | 
               | It is similar to what Codd called adjacency lists, which
               | luckily died in the 80s, because they conflicted with
               | real adjacency lists. recursive CTEs add transitive
               | closure, which when added to FO gets you to L or NL, I
               | forget which .
               | 
               | Still it doesn't matter, the relational part of the
               | relational model is attributes or column names...it is
               | equivalent.
        
               | 9rx wrote:
               | _> the relational part of the relational model is
               | attributes or column names_
               | 
               | The relational part is defined, most importantly, by the
               | set. That was key to Codd's model, and the source of his
               | primary criticism of SQL.
               | 
               | But his ideas went out of fashion long ago. Postgres,
               | _pre-1995_ , was the last time we saw a relational
               | database anyone heard of. Sure, there have been some
               | esoteric attempts more recently to revive the concept,
               | but they never went anywhere. For all intents and
               | purposes the relational model is dead. We live in a
               | tablational world now.
               | 
               |  _> it is equivalent._
               | 
               | It is not, though. In fact, I posit that lists/multisets
               | are easier to reason about, at least where one doesn't
               | have a strong mathematical understanding (i.e. the
               | layman), and that is why SQL "won". A list, if carefully
               | constrained, can represent a set -- which is maybe what
               | you are struggling to suggest -- but that does not make
               | it a set.
        
               | nyrikki wrote:
               | Can you provide any specific situation where the
               | following does not hold?
               | 
               | Especially if I add the constraint that rows have to be
               | unique?
               | 
               | Relations=Tables Rows=Tuples Columns=Attributes
               | 
               | I think we may be from different schools of set theory,
               | where I am from the more abstract direction, where set
               | membership, inclusion and equality are separate concepts
               | and don't need to be decided on to define a relation.
               | 
               | Not that my view is _better_ just different.
               | 
               | I just happened to come through the
               | {{foo},{foo}}=={{foo}} school.
        
       | vjerancrnjak wrote:
       | Just avoid ORM. It's designed to encapsulate, not to be
       | efficient. Lazy loading is part of initial design. Turning it off
       | destroys encapsulation and requires you to know what the code
       | below will fetch.
       | 
       | In that case you might just abandon ORM and preload the context
       | with something more efficient.
        
       | atothayu wrote:
       | this nerdsniped me so hard ty
        
       ___________________________________________________________________
       (page generated 2025-07-01 23:01 UTC)