5 ms·
The bigger point is that all programming is meta-programming in the sense that input traces different paths through your concrete statements based on context -
by javajosh 10y ago
The bigger point is that all programming is meta-programming in the sense that input traces different paths through your concrete statements based on context - which is nothing more than a fancy word for reduction over previous inputs (and it's useful to consider "program statements" to be inputs). A concrete input requires a concrete set of statements to process, selected out of the universe of possible statements. In the OOP style we have a specific way to organize those statements, which defines the "coordinate system" of our combinatorial problem.
Strongly-typed languages like Java or C# really obscure this simple truth, in my opinion. What the OP is talking about is one specific way that it can be obscured. Which is certainly true as far as it goes. But it's not going far enough!
The real problem is that OOP is totally under-constrained for end-user applications. (Although it's perfectly adequate, I think, for modeling formats and protocols).
The only really good way to do applications is as dynamic functions, because there is self-similarity between your program statements and the way you organize them, making your combinatorial problem far more straight-forward. Plus, if you do it right, your function set can fit into on-die cache, and you know enough about your inputs so that you can allocate a fixed, small memory space for any combination of statements are required for a given input (or gracefully error out when your assumptions about input are violated - ideally without even unloading your code).
- owyn 10y agoDo you have any examples of an application which is written this way (as dynamic functions?)
- BJanecke 10y agoMost compilers :)
- Const-me 10y agoI think you over-estimate the share of combinatorial problems in software. There’re a lot of them indeed. But outside niches like compilation and text parsing, they are far from majority. Some problems are bandwidth-bound, like photoshop: if you have 1GB image, you have to process the complete data set no matter the combinatory. Other problems are IO bound, like databases: if user wrote a query that need to do sequential scan over a table, you’ll have do to that I/O. For both classes of problems, OOP is just fine. Another thing is, OOP is better at explicitly managing the state. If you design an app your way, viewing your code as reduction over previous inputs, I expect you’ll struggle implementing state management functionality like undo/redo stacks, and saving/loading your stuff in these formats and protocols.
- javajosh 10y agoThe combinatorial problem is universal. In OOP we organize our processes using objects. Classes (collections of methods, which are collections of statements) are runtime-invariant. In the steady-state, your process handles input as a method invocation (the main(String[]) of a CLI program or the handleRequest(req) method of a servlet, for example). In both cases, the thread associated with the input travels through your code, going deeper, then shallower, deeper again (the depth is the stack frame count). Each time we go deeper (each time we conditionally invoke a method) we are solving a combinatorial problem across our own code-base. We are effectively crafting, at runtime, a unique program (concrete list of statements) to deal with this input. We don't normally learn OOP this way, or think of it this way, but it really is what we are doing. But there are some benefits to thinking in this way. For example, what is an interface? Like all indirection, it's like lubricant. It decouples one set of statements from another, and makes it easier to substitute (or slide) out the second set. And a factory? Well, it produces bundles of statements that conform to an interface. But since we are strongly-typed, the factory is only selecting from a finite set. (In fact, the factory pattern is a perfect example of how OOP practitioners are doing combinatorics all the time, but we don't know it, and we do it crudely.)
- Const-me 10y ago> In OOP we organize our processes using objects We organize our state using objects. Many programs have to deal with complex mutable state. The extreme cases are OS kernel state, or game state in an AAA videogame. For such programs, OOP is the only approach allowing people to reason about what’s going on inside these things. If you don’t have complex mutable state, other approaches might become more practical. One example is compilers; their state is mostly immutable. Another is pure computations without state, especially symbolic computations, like what happens in Maple. > the thread associated with the input travels through your code, going deeper, then shallower, deeper again In many programs, input handling is minor part of overall software complexity. Sometimes, most of the code don’t even run on the input thread. > decouples one set of statements from another, and makes it easier to substitute (or slide) out the second set. Interfaces abstract away arbitrary stuff (statements, data, hardware devices, etc.), providing strongly-typed API to use that stuff, and hiding complexity of the implementation. In some case (COM interfaces), the statements you’re selecting were written in another language, are implemented in another DLL being loaded on demand, run in different process that starts up on demand, or for DCOM even run on different machine. > since we are strongly-typed, the factory is only selecting from a finite set In C#, some class factories take your strongly-typed interface, take other parameters you pass to the factory, and implement the interface in runtime. Because there is infinite set of possible class-factory parameters, that makes the set of statements infinite as well. BTW, this approach is often used in .NET RPC libraries, like WCF.