Elaborating on my vision from my introduction: As...
# thinking-together
а
Elaborating on my vision from my introduction: As I said I don't believe that computation is the future of the software, because it's fundamentally static. Computation can describe how something is processed, but completely ignores context, adaptability, and authority. Programming is about knowledge management and processing, not about the mechanics of how to process that knowledge. That exact flaw was inherited from mathematical notation. In math, a function is a context-free, absolute truth:
f(x) = y
regardless of time, place, or permission. But software does not exist in a vacuum; it exists in a messy, stateful, hostile world. By treating programming as applied math, we trapped ourselves in implementation bubbles. We obsess over the mechanics of the loop, the memory layout, and the specific syscall, while the actual intent of the software rots in documentation and comments. We have enormous difficulty expanding the intent of software because the intent is never expressed in the code itself - only the rigid steps to execute it. This is why we just keep running in circles, rewriting the same logic over and over. We translate the same human intent - "display this document" or "transfer this value" - into a thousand incompatible computational dialects: Swift for iOS, Kotlin for Android, C++ for the backend, JavaScript for the web. We aren't creating new value; we are just manually translating computations across boundaries, because computation cannot transcend its substrate. If a system can reason about itself, it can adapt. It doesn't need to be explicitly told how to do something for every possible scenario; it needs to understand what it is trying to achieve and negotiate the how based on its current reality. In natural language, we refer to concepts via words. Words refer to concepts within a current context; they are not the concept itself. If I say "open," you understand that the mechanics of "opening" a window are vastly different from "opening" a database connection or "opening" a door. You don't need a different verb for each physical mechanism because the context resolves the ambiguity. Current programming languages lack this context entirely. They force the word "open" to mean exactly one rigid mechanism, shattering the unity of the concept across different environments. I think we need a language for intent description, rather than another one for computation. A language where operations are not hardcoded instructions, but negotiated capabilities - where "read" isn't a specific syscall, but a declared intent that the environment fulfills based on what it is authorized and able to do. By decoupling what we want from how the machine achieves it, we can finally unite the ecosystems shattered across different platforms, languages, and hardware. We stop writing software for a specific machine, and start writing knowledge for a dynamic world. P.S. I do have a PoC of intent language, but I'll need to rewrite it from lua to julia, because lua can't do multi-threading. In current state I haven't finished tutorial nor a proper document on how it works, so showing just it's examples usually causes confusion because of new paradigm shift. Anyways I can show it right now, but I need to add description on how to use it.
😍 2
💓 2
👆 1
💡 1
k
What you outline is the distinction between formal systems and informal human communication. Formal systems are closed and fully specified. No context, no ambiguities. That's a feature, not a bug. They were designed for that. Mathematics made a lot of progress when the concept of formal systems became clarified in the 20th century. Automating formal systems via computers has lead to huge progress as well. It won't go way. However, as you point out, formal systems are not the right approach for every problem we try to automate with software. We just haven't figured out yet how to make context-sensitive information processing that has useful behavior, meaning behavior predictable by its users. LLMs can be seen as an attempt to capture enough knowledge about typical contexts to allow natural language specification of problems and solutions. But we try to use them as problem solvers as well, and that just doesn't work. The best we have so far is coding agents, which translate between informal specifications and formal systems.
а
You are presenting a false dichotomy between context-free formal systems and fuzzy, unpredictable informality. The flaw in modern programming isn't that we use formal systems; it's that our formal systems only model computation, not context or authority. We don't need LLMs to hallucinate code to bridge this gap. We need a new class of formal system where context (like scope, isolation, and capabilities) is a first-class, rigorously defined element of the language. By formalizing the negotiation of intent - rather than just hardcoding the mechanics of execution - we can build software that is both highly adaptable to its environment and 100% deterministic. The problem isn't formalization; it's that we've been formalizing the wrong thing.
i
I think there are some interesting ideas in the language RealTalk that is used in dynamicland — it has language constructs that allow you to specify a need, which someone else in the room can satisfy by providing that need in close enough proximity. There are also some good ideas in Jai I think, where Jonathan focused on designing the language to support transformation of the program with as little hassle as possible — by making the transition from "statements" to "statements in a block" to "statements in a block with limited access to variables" to "lambda" to "procedure" as smooth as possible with regard to syntax changes I myself have put together my own approach to low level programming that is a bit intention based I think, to enable linking files that "self organize" by shifting the idea of what a function is slightly
а
Those are great examples of improving how we author and structure code, but they still collapse into context-free computation at runtime. Jai makes it syntactically easy to write a callback, but at runtime, that callback is still a rigid instruction pointer. RealTalk uses physical proximity to trigger code, but the code itself doesn't negotiate its authority or capabilities. The missing piece in all of these is that the running program cannot reason about its own context or authority. I'm not trying to make computation easier to write; I'm trying to make it unnecessary to hardcode the mechanics in the first place. By making intent, context, and authority first-class runtime constructs (via protocols and environmental layers), the execution can adapt to its environment dynamically, rather than relying on the programmer to have predicted every possible state at compile time.
j
I think reasoning is quite related to other representations, but it gets quite difficult for humans quick e.g. https://en.wikipedia.org/wiki/Epistemic_modal_logic . I think we always end up finding that even languages live in multiple contexts, which is why they model the bridge between what is and what is written - code or text in general
❤️ 1
o
Hey there, I find your ideas intriguing I literally started 2 days ago to implement predefined aliases for programming concepts, it is not much yet, https://github.com/uprun/memo-tools/tree/prod/spoken-js I would like to see your PoC but the link is broken
i
Oh, maybe I read you too literally. It happens sometimes for me. Do I understand correctly if what you're thinking about is on the far end of a spectrum including logic based languages (specify what you want and what you have) as well as interfaces to hardware (specify what you want and let OpenGL and friends translate it for you) and I guess philosophically also cross platform libraries (same but swapping out code, "code as context") which in the old school actually also is part of what syscalls are (an interface to the OS context, specify what you want "open a file" instead of going to memory to find an address and map some pages). So taking that thinking further, into formal representation? I'm curious if you'd enjoy (or already know of) NixOS and how it created a language to specify things (as opposed to Arch Linux and friends where you rather focus on the processes) PS: If you want to dive truly deep I'd recommend getting into David Ackley's robust first programming ideas. I think you might find those interesting, and a viable theoretical groundwork to build something contextually aware and reactive upon. For me his work really enforces why I personally am so disinterested in the current implementations of ML — they mostly scale up the capacity to fuzzily deal with larger and larger amounts of known state, but are in most cases helplessly unprepared by design for unpredicted or not-yet-reasoned-about state. Also curious about your PoC!
👆 1
💡 1
e
Highly intrigued by your post. I'm wondering what the practical examples are. You mentioned asking "open" to a person, but in a world designed using OO concepts, you would not ask a person to "open". You would ask a door or a window to "open". It's the door's/window's responsibility and therefore its known behaviour. There you could also have context which can/should influence behaviour (which we often can't really specify easily or have to implement very specifically not generically as I think you seem to suggest). Would love to see some examples from your PoC to better understand it I guess. Are these much higher level constructs than what we currently use in programming (because of the mentioned instruction stream [my words])? Is it more about defining the logic and let the application/objects/things decide how to perform any required behaviour? Please, please tell us more! 😄
❤️ 1
а
https://github.com/MegadronA03/NegI here it is, I had to update some stuff so people won't instantly be lost.
👀 2
g
+++
а
The whole context is immutable transactional thing, meaning there are no thing as variables (think of it as Git DAG). Instead the user changes context with effects that are stored as transactions, they could be added or substituted with another effect, but not overwritten outside of current layer. When there are nothing to execute within current layer, it's killed with all of it's effects (meaning the only way to carry effects outside is through return). Manifest is a manifestation of abstract concept (or implementation of it). It holds a protocol (what can be done to it) and an opaque state. The closest thing would be a ship cargo that you can only interact with via protocol it's provided with.
g
That exact flaw was inherited from mathematical notation.
I see the fundamental flaw as being the one-size-fits-all problem. We seem to believe that it is necessary to force all concepts into single GPLs (General Purpose Languages) and single notations instead of using multiple notations (programming languages) to co-exist and to be composed into real-world solutions. Reality is asynchronous. The notation f(g(x)) implies synchrony, hence, it cannot deal with asynchrony. Hence, closed-world formalization denies reality. Only a small slice of reality can be described in a closed form (e.g. for example the 5% formalizable vs. 95% pushed aside as "dark matter" in cosmology). Belief in closed-form formalization encourages people to disregard the greater majority of reality.
P.S. I do have a PoC of intent language, but I'll need to rewrite it from lua to julia, because lua can't do multi-threading.
Multi-threading is but a simple trick that can be implemented in assembler, hence, any language patterned on assembler can do multi-threading. The implementation of multi-threading is actually the implementation of synchronous time-sharing, which has been misconstrued to be equivalent to asynchronous parallelism (it's not the same). The idea that a language "can't do multi-threading" is simply false. If you can build queues (queue classes, data structures in assembler) and have first-class functions (closures, pointers in assembler) then you can do multi-threading. Multi-threading simply /simulates/ parallelism, it is not asynchronous parallelism. We have many tools for wrangling languages and it is entirely possible to - easily - create mappers from meta-language to existing language. I would suggest that you don't waste time porting from lua to julia but spend time rewriting the lua implementation in a meta-language (your DI language, say), then create a T2T (text to text) transmogrifier that spits out lua, julia, python, C, Rust, etc. code from your DI code. (This kind of thing has been done since the early days of computer-ing, e.g. Prolog is a non-functional language. The "engine" for Prolog was built using functional, synchronous, sequential building materials, like other languages (FORTRAN, as I understand it), Tiny Basic was written in assembler, SmallC was written in pdp-7 K&R C, Forth was originally written in COBOL, etc).
а
that would cause infinite recursion, because the thing is NegI can't do maths and ask host for that, writing another language for the language is kind of a time waste, because the Artifacts (host authority on NegI side) are constructable from NegI runtime, so I had 2 options: LLVM or Julia (some lang with eval and low level access). Since I was making a reference implementation for easy porting, Julia code inside Artifacts would look more readable than LLVM IR.
@Erik Stel In OO, you ask the Door to open because the caller holds a reference to the Door. The caller dictates the mechanics:
door.open()
. This is exactly what Paul is pointing out with
f(g(x))
- the caller strictly defines the synchronous chain of who talks to whom. In NegI, the caller only expresses the intent:
open
. They don't hold a reference to a specific object; they throw the intent into the current KES context. It is the environment that finds the Manifest capable of fulfilling
open
- whether that's a Door, a File, or a Network Socket-based on dynamic protocol negotiation (
capcheck
), not static interfaces. This is how it mirrors natural language. If I say 'open' in a room with a door, the door handles it. If I say 'open' at a computer, the OS handles it. I didn't change my intent; the context changed the execution. OO can't do this without rigid Visitor patterns or dependency injection frameworks. NegI does it natively because context is the runtime.
❤️ 1
👍 1
@guitarvydas Regarding the transpiler approach: The reason I'm porting a runtime rather than building a T2T transpiler is that NegI isn't a syntax; it's a semantic substrate. If I transpile an intent into (for example) Python, I also have to transpile the KES (context management), the Dispatch (negotiation), and the Capcheck (authority) into Python. If I have to rewrite the runtime for every target language, I've just multiplied my maintenance burden. By implementing the reference runtime in Julia, I get the
eval
for Artifacts, the C-FFI for hardware, and the shared-memory threading natively. Julia becomes the substrate where the physics of negotiation live, and I only have to write those physics once.
k
So... I am in a room with a door and a window. I say
open
. What happens? More precisely, how is the decision made?
❤️ 1
Back to my theoretical argument: every formal system has a non-formalizable context of use. Like a physical machine, the formal system is deployed to perform a specific task that makes sense to someone in that context. This means that whatever you formalize isn't "the context". It's one layer more than your previous formal system.
d
While I appreciate the higher level intent and distinction, can you provide an example of what the sweet usecase of such a system could be? Yes, writing code has always been 80% bureaucratic work mathematically circumscribing uninteresting context. The greatest deployments of software before LLMs have been in replacing repeatable, static processes that are beneficial to scale up. What you're describing isn't LLM based agents or AI, symbolic of learnt (right?). So I guess my imagination fails me for what kind of deployments or problem solving I'd with an implementation like this. Is it like logical programming?
☝️ 1
1
k
Is
open
expressed nominatively, with those 4 letters, or with some other form that captures the semantic that can disambiguate between opening doors and file handles?
а
@Kartik Agaram In NegI user operates with the backend via labels and how they interact with each other. Label is a Manifest that query the current context to resolve a name it holds and find relevant underlying manifest . This means that usually it's not defined as
door open
, but
something open
and that something could be anything. Same label can't reference multiple thing within 1 context, because it's transfered between manifests. So if within 1 room there are window and a door that was assigned label
something
that label is resolved to the last one that was assigned label
something
@dman-os I made with these goals in mind: At the beginning of it's development I wished for a compiled language that had no distinction between compiler directives, macros and the language itself. This forced these design constraints: 1. Absolute crystal clarity of how some feature is implemented on host side 2. 0 assumptions on what authority is available on the machine 3. Substitution of anything, because anything could be whatever it is due to difference in implementations and 0 assumptions (we do not trust anything, therefore we must check) 4. Make interpretation result compile 5. Explicitly define how effects propagate (because of ability to substitute anything) 6. Make this system as minimalistic as possible. this enables next things: 1. NegI can run on anything given HAL (host/hardware abstraction layer) and in NegI's case thats Artifacts. Artifacts define implementation of some host capability. 2. compiler, optimizer, interpreter and parser are libraries that user is free to change, ship or use anywhere within NegI environments. 3. decompilation into NegI is more extensive than C one, because theoretically NegI abstractions can map back on to any binary, given Artifacts and the abstractions. 4. Absolute Capability Security. "Imagine loading a third-party analytics plugin. In Python/JS, it has ambient authority—it can read your files or phone home. In NegI, you load the plugin into an isolated KES layer. It only has the capabilities you explicitly inject into its context. If it tries to dispatch
read filesystem
, the protocol check fails, because the Manifest for the filesystem doesn't exist in its context. You don't need sandboxing wrappers; the lack of capability is the sandbox." 5. The Cross-Platform Intent. "Imagine writing a UI app. I want to express the intent
save document
. In a computational language, I must write conditional logic:
if (OS == 'web') { localStorage.set() } else if (OS == 'desktop') { fs.writeFile() }
. I am manually mapping intent to mechanics. In NegI, I just dispatch
document save
. The KES environment running on the web provides a Manifest that fulfills
save
via LocalStorage. The KES environment on the desktop provides a Manifest that fulfills
save
via the filesystem. The source code is identical; the context adapts." 6. Frontend (parser) is decoupled from the backend, because backenmd expects only Manifests and it doesn't matter from what place they are coming from. This allows to make other modules that emits Manifests (like foreign language parsers, decompilers and etc) 7. Reinterpretation of existing code allow to mock literally anything without DI pattern. This allows to add logging to anything (including maths), and allow to compile code just by evaluating it.
@Konrad Hinsen You're theoretically correct - we can't formalize reality all the way down. But practically, we don't need to. Right now, the boundary between formal computation and informal context is drawn inside our code, at every function call and every global variable. By pushing that boundary down to the OS/Hardware interface (via C-FFI and Artifacts), we push the informality to the very edges of the system. KES formalizes the software's context. The informal reality is isolated to the Host boundary. It's not infinite regress; it's containment.
i
Tried it and got almost nothing to work. Most of the examples just print an internal datastructure for the parsing to stdout. I see that you manually added in the basic operations for numbers, but you did not add precedence rules to the parsing, so giving the repl "1 + 5 * 100" outputs 600. I think the potential confusion you say might experience from people might be less due to a paradigm shift and more due to (a) the very early stage of the prototype, (b) some last minute adjustments that wrecked it (improbable though, went quite far back through git history) or (c) doing a bit of a too large project too early maybe (one of your commits say that you're learning git). The whole thing feels more like an art project. The original name "ENIGMA" that you used for the engine would probably be a tad more on the nose if it is, at least from my ideas of aesthetics. I could be missing something (I have a long experience of approaching things in a too complex way where it is hard for people to see what I'm trying to communicate) but this seems a bit... vibe coded maybe? Is that too much to assume? It's just weird to me why all comments in the examples are in quotation marks, which is not supported in the repl, and the proof of concept has no practical examples or tests. There are spelling mistakes sprinkled throughout, even in places that seem copy/pasted and really should not have spelling mistakes. They are usually single character mixups or additions, which is a common strategy to bypass plagiarism or AI detection. The other repos of your's have made similarly little sense, even though their goals are far more approachable. Most of your commits seem to clean up seemingly nonsensical code. Your answers really does not address much either. Are your responses also generated? They seem like it as well, slack doesn't allow me to view edit history but the edits I've noticed are pretty weird as well. And again, so sorry if you're just a neurodivergent weirdo like me. I too use em dashes for style.
k
In general the way you phrase the problem resonates a lot with how I think of things and have thought for 10+ years over multiple projects. One way I tend to put it is what we do tends to often outlast the people who created it, and why we do it as we do it is easily lost. Does that seem to fit with your thinking? In the past I tried to chase down intention by using tests and capabilities everywhere up and down a software stack. Part of the problem is that one person's why is another person's what. I repeatedly find that I have not learned enough from many past innovations. Parnas's modules introduced the idea that every boundary should hide one single design decision. ADTs introduce the idea of an opaque implementation that you can only modify through the interface. Design Patterns. These innovations did ripple into practice, unlike many others. But in the process they somehow lost their life force. I think they lost it by being over-applied. The crucial thing about modules isn't to create lots of them, it's the binding with design choices. The crucial thing about ADTs isn't hiding and then adding getters and setters, it's creating a well-defined algebra of operations_._ In a healthy context, opportunities to create new modules and ADTs and Design Patterns should be few and far between. Usage should be characterized with restraint above all. But when they enter a social milieu people notice that status accrues from creating them, and "inflation" results. I think this is the thing that past innovations have failed at. Just food for thought as you work on the next innovation. It's important to think about what behaviors you want to encourage and what you want to discourage. Don't create tools that make it easy to do that which you want to discourage. Defining modules and ADTs should be harder than it is, IMO. But I don't know how to do that.
а
Well that's part of a reason on why I don't want to go full public with NegI just yet. But at the same time I do need people, so my ideas and vision can be challenged and tested.
Because for example I still have no idea how math and strings should work in NegI. I'm referring to default type that the user will be introduced first, before they substitute it.
The conflict why I don't know stems from the fact the more capability Number holds, NegI becomes harder to adapt or I should somehow explicitly explain that not all Number capability is guaranteed to work? Other way is to delegate additional capability of default manifests over to libraries...
❤️ 1
though that doesn't solve a thing regarding what is Number and String generic representation on it's own. Inside development environment sure, they must be able to do anything (Number could be Rational that consists out of 2 BigInts). I think I should make spec for development environment, rather than what NegI should inherently just have by default anywhere.
@Ivan Morén I'm not a native english speaker, but I do read through everything I send, and I do use AI for translation and text structuring purposes (I have trouble structuring long texts, and AI partially helps to mitigate that.). Precedence rules are intentionally absent, because that would extremely over complicate the parser and how combinations are resolved. At some point I thought of adding it, but in all of the cases that introduced lots of indirection and chaos. I didn't used AI to create NegI. The extensive amount of comments comes from the reason that I needed to find some reference material to inspire myself and make AI easier to find that material. So that's is the reason why it looks like art project, because at the core I have no idea on what NegI actually is nor how some parts of the project must work. The thing is like 5 months old, and prior that I was establishing goals for like 3 years, by trying to concentrate every language that I have tried (I tried about 30 of them).
❤️ 2
And I literally had no one to help me. I was making NegI alone. That is the reason why I'm here.
🤝🏼 1
g
Regarding the transpiler approach... My understanding of what you are saying is that you are writing a Negl engine (you call it a "runtime") in Julia. Then, you intend to use that engine to run Negl. I am trying to suggest writing the engine in something higher level than Julia (which you can easily invent on the fly). There is no need to write T2T tools, those exist - OhmJS+JS(strings only, no classes and other complications), awk, stuff I've been experimenting with (T2T == OhmJS + (my)RWR), etc, etc. All modern computer programming languages boil down to machine code. If you use Julia, it becomes machine code, if you use Rust, it becomes machine code, etc. If you use XYZ (Julia with your hacks on it) to write the engine, you just "push a button" and get runnable Julia code and get runnable Python, and get runnable ???. I.E. just one source for the engine --T2T transmogrifier scripts --> engine code exhaled in many languages. The "syntax" is for building an engine that can run Negl. The "syntax" is not directly for Negl. Cranking syntaxes is easy these days. You can hack together an XYZ by writing Julia and thinking about "how will this be done in other languages?" - if there is no direct mapping, just insert a phrase (a "macro" phrase). Write a grammar for XYZ (I claim that this will be easy), then write JSstringsonly or RWR rules to transmogrify XYZ syntax into suitable code for other languages. [I created a higher level "spec" for a message-passing (i.e. "threaded") PBP engine this way: it was originally written in Odin, then in Python, then in 1kLOC ".rt" which currently transmogrifies into 1kLOC Python, 1.2kLOC JS, 1.4kLOC CL, ..., all doing green threads from scratch (without leaning on an O/S)] aside: Are you aware of @Scott's take on message passing with late-bound semantics? Maybe a source for brain-picking?
👎🏼 1
а
In summary I started programming like 14 years ago and actually started to do serious code 8 years ago. I have other code, that I can't post on github due to either legal reasons (anticheat bypass and tooling for modding and leaking update info in game Crossout; some game mods that ships with proprietary code) or just because visual programming was used (3D software renderer and slab memory allocator in Fancade). I think me being ignorant made NegI the way it currently is.
k
What you can uniquely contribute to the world comes from your unique strengths and weaknesses.
s
Hey! Is that thumbs down aimed at me @Kartik Agaram? 😆
👎🏼 1
😄 1
а
@guitarvydas, you're right that transpiling syntax and static logic is a solved problem. But NegI isn't a static logic; it's a dynamic, self-reflective runtime. The T2T approach breaks down at the boundaries of
eval
and authority. An Artifact in NegI isn't just data; it's a string of host-language code injected with a specific context (
FLESH
) and evaluated at runtime. A transpiler cannot automatically map Julia's
Core.eval
to Python's
exec
or C's compiler API without writing massive, language-specific runtime polyfills. Furthermore, the whole point of choosing Julia is its native substrate capabilities:
ccall
for zero-cost C-interop,
llvmcall
for ASM, and native OS threads for parallelism. If I transpile OPHANIM to JavaScript or Python, I lose the native C authority and I lose true parallelism. I end up simulating the physics of Julia in languages that lack its capabilities, which defeats the purpose of having a substrate that can actually reach the hardware. I'm not building a syntax to transpile; I'm building a physics engine, and the physics depend on the substrate.
@Ivan Morén About NegI names: I'll start from the very beginning Pre-implementation phase (where I was setting up goals) • Array++ • ObjectFlux • ExpressionFlux (or ExprFlux) • LayerFlux • CanvasFlux • ImageFlux • CFlux • FOX - Fabricating Objects and eXpressions • Loom • C4 • Moss/Mold Implementation phase: • Uncode - Universal Composition Descriptor • NegI - Negotiation Interface or Negate Identity • FINAL - Final Is Not A Language • ENIGMA - (I don't remember abbreviation, you can see it in git history) • OPHANIM - (for the backend, picked because translates to wheels) I thought of not using ENIGMA, because there is already project called Enigma that's used for language processing or something like that. Though the main reason I dropped most of these names because of SEO (the name might conflict with search results)
💞 1
Basically the project started when I saw a joke esolang "Table" that defined computation through tables and indexing, so I thought of making it practical, by bringing stuff from other languages, while trying to keep the core grammar as small as possible.
a
The parts about encoding intent and context resonate strongly with me. I think it's interesting that you draw a distinction between intent and computation, because my idea of "intent" is highly computational. Specifically, everything in a computer exists to signify some action in the real world, and a context is a mapping of intents to actions (also authority, etc). Implementation-wise, I'm thinking algebraic effects, which are also expressive in lots of other neat ways. (Also, hi fellow Andrew. 😄)
👏 1
...I don't think I did a good job expressing myself there. Basically, as far as a computer is concerned, intent always ends up manifesting as data and/or control flow, which are themselves two sides of the same coin: data is crystallized control flow.
а
Well when I was making NegI, I tried to abstract myself from computation/math and look into the knowledge behind actions that enable description of description. Because ultimately formulas, code, blueprint are all descriptions.
NegI forces the user and runtime to work with uniform black boxes(Manifests), that can only interact with each other according to their protocols(via Negotiation). The boxes can't inspect their contents without knowing if content matches the intent they are trying to perform on. That's is the reason for capability check existing, because it allows to make sure that certain content can only get certain transformations.
a
Hmm, yeah, as far as I can understand it that's a rather different take on "intent" than mine. In my view, something timeless like
f(x) = x^2
is an intent. By itself or in composition with other bits of intent, you can re-interpret it in different contexts: evaluate it with various number systems, compile to various forms of machine code, do abstract/partial evaluation shenanigans on it, take its derivative, etc. In some cases you can even solve it for x and run it backwards. But at least for some of those you do have to be able to inspect it deeply. I think that's an important way to get more value from a precise intent. I haven't figured out the exact line between a context and an interpreter/simulator, but they're close; a simulator is definitely a context, and a simulator sees everything. (Simulator is probably also responsible for security FWIW) There's still some overlap in views though. "DisplayDocument(content)" has a similar timelessness to math, as long as the document content itself also does, which it should in my opinion. I've thought along a lot of these same lines and eventually came to the conclusion that a good enough intent language is indistinguishable from a good enough programming language. The tricky part is the interface with the context, making it general enough that code/intent written against it can be meaningfully recontextualized. Or something like that. Still figuring it out. 🙃
k
@Andrew F the way I tend to explain it is: you can have the exact same line of code execute in two different situations, and the intent can be very different. It's worth rereading the legalism paper: https://feelingof.com/episodes/065. If you tell a person to do steps x, y and z there's usually some intent leakage so they understand which parts are load-bearing and which parts are incidental. But when you tell a computer the same steps, every single bit becomes ironclad "thou shalt." So it's impossible to convey intent by the lines of code that run in production. You don't know which lines of code were arrived at after considering 16 million options, so that they must be exactly so, and which lines could be one of 2 million different formulations and the author wouldn't care.
a
@Kartik Agaram that feels like yet another, more abstract sense of "intent" than I'm going for. For me at least, part of my idea of "good enough intent language" is the ability to leave non-load-bearing aspects unspecified (and/or refine them later). (Obviously this isn't new, it exists most famously in the form of declarative programming: a SQL query leaves a lot unspecified.) Ed: but we should probably either nip this tangent or make a new thread.
k
I don't understand what a sense of "intent" that is identical to "computation" buys you. Why not just call
f(x) = x^2
a computation? It's easier to understand a sense of "intent" that is "everything but computation". In this framing, SQL gets closer to intent than C, but is still not the intent. No computation can ever be the intent. I don't know either, but it doesn't seem unrelated to the topic at hand. I'd say until proven otherwise there is only one sense of "intent" that we're all circling.
"The letter S" by Don Knuth is an interesting case study. For most people, the "intent" of pressing the letter S would be "I want the reader to see a legible letter S, as understood in our shared cultural mileu." Don Knuth is concerned with making the letter S look identical to what he's used to in a very specific font. In getting the pixels just right he's able to deduce certain details of what the typesetter decided. But I'd claim there's a deeper intent that even this doesn't uncover. The typesetter figures out mathematical properties based on how they look to the human eyeball, at scale, given a particular sense of what causes eye strain, what paper was like in the eighteenth century, etc., etc. So the challenge for anyone interested in researching intent is: how can you encode these 3 levels of intent. Maybe the third is too hard, but even 2/3 would be an extremely interesting case study. This is what I meant above by "one person's why is another person's what." Intent is not a single level. To capture intent you have to support multiple nested levels of intention somehow.
i
@Kartik Agaram & @Andrew F Just want to throw in that in this discussion of "intent", one of my favorites is HTML/CSS. Express your intent, and depending on the browser's capabilities it will do its best to honor your wishes. I think that it also shines a light on the other part of intent: Expectations. An HTML document could very well be adapted into other media, perhaps a slide presentation, a movie or a typeset book. But most HTML pages are written with certain expectations of where and how it will be viewed. If the author expected the structured text to be adapted into those formats, they probably could make choices that work well for that future format. Accessibility developments in HTML5 (if memory serves me) have standardized how to support some of these alternative reading formats (screen readers, etc) while still also being a good fit for the norm So intent and expectations mean that it all boils down to communication. Our natural language fails us sometimes as well, but usually works well enough to get by as long as there is room for follow up questions or clarifications. Just this weekend I've noticed so many "can you open that cupboard" "no, no, no, that one" — that I think that it is very clear that context is only enough when intent is known, common ground is established or there is enough information to make educated guesses, and as soon as things leave the well traveled paths misunderstandings occur a lot more frequently. I think the idea of a language oriented around intentions is really interesting @Андрей Бурлаков, and it touches on many subjects in languages that are needed to make them friendly and human-interfacing. How they handle the cases where ambiguities arise I think is the big question, and maybe the one that I think is my biggest question for your project <3
💯 3
❤️ 3
k
Mostly agree, but I want to also caution against conflating intent with DSLs like SQL/HTML/CSS. A DSL captures one level of intent, but as I said I believe intent can be multifaceted. The same exact computation can stem from very different intents. So creating a new DSL for every possible intention seems unscalable. I think there's no getting around the fact that we need a way to express computations that we don't care about. A complex math formula in one place may need to be exactly so, and in another may be within a function called
rand
and so be one of a thousand valid candidates. You need something more than computation to express these differences. In the past I've explored prose, tests and formal methods to express them. But there may be other approaches.
💯 3
g
Are these different?
f(x) = 2 * x
f(x) = x + x
a
@Ivan Morén The expectations thing is a big part of what I referred to as generalizing the interface between the intent and the context. HTML written for the specific context of a browser with JS, LocalStorage and the rest won't work well converted to a docx. But on the other hand, maybe there's some more general thing the document (app if we're honest) actually wants, e.g. an interaction pattern or state management, that can be equivalently implemented in other contexts. Which gets to where I absolutely agree with @Kartik Agaram: specifying intent as opposed to writing a program is very much a matter of leaving out stuff you don't care about. One of my longtime aphorisms/guiding principles is "As Specific As Desired". No more.
💚 1
@guitarvydas to the extent the question can be meaningfully posed and answered, mostly yes. They only begin to be the same in the context of an algebra like a ring: we're all very used to that context, but in the grand scheme of things it's quite narrow. At a mechanical level, consider reckless operator overloading, algebras with only one operator (e.g. group and its friend group), freaky non-distributive algebras that must surely exist, etc. Less mechanically, and especially where a question like this appears as part of a larger problem, it's easy to see how you might have arrived at 2x and x+x by very different semantic paths. In one, the concept of scaling by two appears directly, versus a situation where the general case is adding two values, and there's a specific case where those two values happen to be the same.
k
The main difficulty I see with the "care about" framing is that there things that I tacitly care about, i.e. that I take for granted. The above example by @guitarvydas is a good illustration. Obviously the two lines are different syntactically. The question is if we expect them to be semantically equivalent. There is no explicit context that would suggest "yes", but the symbols suggest a context of arithmetic, in which we take equivalence for granted. Having to state this explicitly seems onerous, so we prefer not to have to do it, but we still care about the context being used as expected. There are lots of similar examples in which the symbols used in code (variable names etc.) point to a context of usage that is not encoded anywhere at the level of programming language semantics but which matters for the program's correctness. This sounds like part of the problem that @Андрей Бурлаков is trying to solve, though I have to admit I don't yet understand how.
❤️ 1
Related: "System of Names" on the Design Patterns Wiki (the original Wiki): https://wiki.c2.com/?SystemOfNames
😮 1
👆 1
💡 1
p
Hey! I found this actually resonates with some of the article I came across recently, specifically wiht elephant 2000 https://www-formal.stanford.edu/jmc/elephant.pdf , John McCarthy actually envisioned the future of programming to be exactly what you described, a intention driven way to talk with the system, except he formalized the intention driven algebra into Situation Calculus https://en.wikipedia.org/wiki/Situation_calculus, I am thinking maybe this resonates with your idea as well
😮 2
🎯 1
g
One must be careful to understand that words carry much more baggage than just their literal dictionary meaning. Words Inference: each consumer of words can get a completely different meaning from a phrase, hence, one cannot always achieve perfect transmission of intent. Great songwriters make their songs touch many people, great software architects arrange designs in ways that are more readable. Great code is not always great architecture. Code is for machines. Arrangement of code to express design intent is for people.
Are these different?
f(x) = 2 * x
f(x) = x + x
If one considers the arrow of time, instead of just the result, one concludes that these are different.
а
For some reason the initial thread got stuck in "Loading history..." for me, so I couldn't reply to anyone. Currently found a workaround.
There are lots of similar examples in which the symbols used in code (variable names etc.) point to a context of usage that is not encoded anywhere at the level of programming language semantics but which matters for the program's correctness.
I did tried to solve this and actually succeeded, but this also introduced parts where I had to keep it extremely minimalistic (at some point of the development I considered some ways to not hardcode brackets and
;
,
into parser), but I eventually left the parser as it is, just to make PoC within months (got this within ~5 months) and not year. This also forced me to make all possible potential ways for the user to encode semantics from the language itself. This is the reason for protocols, artifacts and no math expression precedence, because I couldn't find a way to make it safe for the code readability. Like imagine if user could make custom order of precedence for any label (aka name token that can be a symbols or cname), that would overcomplicate an output of a parser and create total chaos where no one can be sure how the thing should be executed. That's also a reason why I made parser just be another separate entity that can be replaced during runtime.
>
f(x) = 2 * x
>
f(x) = x + x
I'd say for the intent perspective they are indeed very much different. But not for a arrow time reason, it's about assumptions, about names/symbols we see here. By that I mean there are nothing that states
x
type nor for anything else. This means that `x`'s understanding of
+
can be very much different from user's assumption about addition. Just thinking that
this might be JS
is enough for this to break.
Also an update for NegI, I'm ditching Julia in favour of Janet, because Julia don't allow to create anonymic definitions. I also had C + libtcc, but that would make reference implementation buried in machine specific code. Also looked into Deno (JS/TS runtime) but I'm still conflicted about it.
decided to ditch the Janet and go straight for the C + TCC. Almost finished with the memory layout of structures (I'm mostly using arena allocation, because the system is immutable and append only)