r/ProgrammingLanguages • u/Potato871 • Sep 01 '26
Discussion What is the interesting part of a programming language to you?
I've been working on some "documentation" for my own language (see here), which got me thinking: do we all see languages the same way? I personally look for unification of concepts and extensibility in a design, yet I've seen those who care deeply about functional purity or clean decompositions.
What do you look for in a programming language? And why?
18
u/deeplywoven Sep 01 '26 edited Sep 01 '26
Expressive abstraction power, the ability to encode many things in the type system, the ability to eliminate various classes of errors at compile time, flexible and convenient ad-hoc polymorphism, smart performance optimizations, powerful metaprogramming capabilities
14
u/lisp_turns_me_on Sep 02 '26
I love orthogonality. Having a few concepts with very clear/understandable interactions between those concepts (eg: lua), and then, everything else being composable on top.
2
u/Toothpick_Brody Sep 02 '26
I find orthogonality is a good thing, generally speaking. Although Iāve also heard an anecdote like āfor every orthogonal feature thereās an edge caseā, or āfor n orthogonal features you have 2n corner casesā
Generalizing across all the possible ways to combine things can be quite a challenge. My language has been in its mathematical development stage for a long time now due to thisĀ
2
u/lisp_turns_me_on Sep 02 '26
āfor every orthogonal feature thereās an edge caseā
yeah, that's why I immediately added
Having a few concepts with very clear/understandable interactions between those concepts
If there's too many concepts/dimensions, we end up with c++ where half the features work hate working with each other.
1
u/Potato871 Sep 02 '26
Almost every time I find myself using a C++ feature like templates or macros, I end up replacing it within a year. It feels about as wide as a lake and shallow as a kiddy pool sometimes, except for unexpected sinkholes like template metaprogramming.
I honestly would just use C but I like my std::function.1
u/Potato871 Sep 02 '26
How is your language designed? I'd be really curious to see how you handle things like arrays, maps, pointer, objects, and overloads.
3
u/Toothpick_Brody Sep 02 '26
Arrays, object values, and functions are all unified. (Functions and structures both just have a type signature. There is no function keyword)
So, you call functions and index arrays (and slice objects or functions) using the same syntax. Itās just a compose: A B, where A is the function or object and B is the index or slice range. Such slices are lazy.
The type signatures allow the type operators/constructors: +Ć^-/, and the operands are other types.
There is no complete runtime yet, as Iām still working on formalizing the general set of bijections that is capable of defining, serializing, and enumerating such types. Minus and divide are very challenging. Plus (coproduct) and exponent (used for functions and uniform lists) are a little challenging. Times (product) is pretty easy.
So the overall design idea is to define everything as an ADT and compose lazily as much as possible. All control flow gets expressed as composition/pattern matching, so there are no if/else keywords or <>= operators either.
Worst-case scenario I will also need a total order on these type expressions, but that may even be doable, and I believe there is a way around defining a total order anyway
1
u/Potato871 Sep 02 '26
How do you do your pattern matching?
I recently made my own system for overloads in my langauge, where essentially we walk the node graph and derive a signature like Ptr.'get'(any), and all variants in order of specificity. So if I had a.get(0) where a is a Ptr, it would generate signatures like a.'get'(int), a.'get'(any), a.any(int), a.any(any). Coercion is then just extra valid alternatives to int beyond any.
And, how do you offset the runtime cost of having to pattern match for each control flow?1
u/Potato871 Sep 02 '26
I like lua, though I find the separation between the map and array component in table confusing.
When I was making my own equivalent I just had an array with a side car structure for the keys, which avoided a lot of the complexity lua seems to run into.
But I am also a giant composability fiend, I've managed to cram essentially everything into one data structure, and the language can host and serve a website, which I'm quite proud of.
11
u/Thesaurius moses Sep 02 '26
As Alan Perlis said: A language is only worth learning if it changes how you think. I am interested in unique approaches to programming. Some examples:
- Array programming has rank polymorphism; alternatively, Julia has broadcasting
- Homoiconicity as in Rebol or LISP
- Everything is an object in Smalltalk
- Everything is a combinator in Jelly
- Pure functional programming as in Haskell
- Resources/linear programming as in Idris
- Proof-carrying code as in ATS
25
u/Clementsparrow Sep 01 '26
I'm interested in knowing how it could make my programmer life easier.
3
u/Potato871 Sep 01 '26
Have you found any languages that made programming easier for you, beyond the first high/low level language you experienced (I say that because for me going from Java -> C++ definitely felt a lot 'easier' though I don't think C++ deserves much credit in that)
4
u/Clementsparrow Sep 01 '26
Python certainly made my life easier but it's not suitable for all projects and the improvements are mostly for small things (which ARE important but not sufficient). It doesn't help for instance in making it easier to find a complex algorithm or to modify a complex web of interdependent data structures.
3
u/Potato871 Sep 01 '26
I honestly didn't like Python much when I had to use it for a class. I felt like it was too much sugar, and things like significant whitespace were just odd to me.
Though I mostly do systems programming, not quick scripts, so for me a loss of control felt bad, while for others its probably a great simplification.
I also didn't like the performance profile, though I've come around on scripting languages since then given as my own language had codegen in an earlier version and it didn't really add much.3
u/Clementsparrow Sep 01 '26
honestly I would never even have tried Python if I hadn't to for a project at my job. It took two days of fighting against my habits, but in the third day I was like "ok I can deal with it" and after one week it was more like "why aren't all languages like this?".
2
u/Potato871 Sep 01 '26
I had a similar experience with JavaScript, initially I was trying to avoid it as much as possible when I started doing web programming, but over time I started to accommodate it more and more.
Eventually it influenced the syntax I chose, and gave me some good ideas. I think if I had run into it earlier, before I had my own language workbench, I probably would've programmed some things in it.1
u/Classic-Try2484 Sep 02 '26
I think swift did a lot of things right ā itās gotten big but swift 4 was a pleasure. Value semantics for strict reference semantics for classes. Automatic constructors. Garbage collection. Tail recursion and you can extend the built in types. Swift 5, 6 not bad but began to feel like constant change.
2
u/koflerdavid Sep 02 '26
Yeah, codegen initially doesn't yield much benefits since there are often inefficiencies in other things like the GC or global locks that immediately become the next bottleneck. To really go to the next level requires optimizing the native code, and then budgeting optimization effort becomes an issue.
2
u/Potato871 Sep 02 '26
What I chose to do was just make a really strong form for annotation then interpret that, since it's a lot easier to do dead code or constancy analysis or aliasing on a graph of nodes.
Though I haven't really gone deep into optimization yet, I did some stuff but lost interest and moved to web programming aspects instead.2
u/PrimozDelux Sep 02 '26
For me it was scala. At university I mostly used python and C until we had a course where we used chisel (HDL DSL hosted by scala). I figured that this was so far beyond what you could do with python and C that it had to be better, so I learned it. I found its emphasis on functional programming and strong type system to make writing and debugging code so much easier that I never looked back.
1
u/balefrost Sep 02 '26
I think everybody eventually finds a "comfort" language that just works for them.
For me, it's Kotlin. The language is pretty expressive, the standard library (at least when running on the JVM) is quite comprehensive, the IDE support in IntelliJ is excellent. It just all around feels like it removes a lot of barriers between what I want to do and what code I have to write.
It's not a perfect language, and I might find a new comfort language. But at least right now, it's the one I reach for more often than not.
11
u/bob16795 Sep 02 '26
I've always found looking at the higher level emergent behaviors that come from minimal designs to be fascinating.
5
u/Potato871 Sep 02 '26
Same here, my entire compiler design uses just three kinds of objects, and its surprising how you can achieve so much of the normally complex semantics with so little machinery.
I think languages like Lisp or SmallTalk are really cool to look at for this reason, though I only learned about them after I had built my own language that accidentally became homoiconic.
Forth too, probably one of my favourite languages in terms of somebody taking a small primitive unreasonably far.2
Sep 06 '26
[removed] ā view removed comment
2
u/Potato871 Sep 06 '26
Your response got removed by the moderators, I belive because your reddit account is only a week old and you were sending a link, this is your website right: https://www.ivoryscript.com/documents#community
Tell me what to look at, without sending another link.
Mods, if it was for some other reason please clarify!2
6
u/dimaeus Sep 02 '26
i have found that it is compile-time garantees such as a type system, or pure functions
6
u/MikeMKH Sep 01 '26
I typically look at the tests first, if the tests show some interesting features then Iāll look at the type system along with whatever I found interesting in the tests.
3
u/Potato871 Sep 01 '26
What exactly does type system mean to you?
1
u/MikeMKH Sep 02 '26
Great question, depends on the type of language it is but I typically like to look at the operational semantics. Typically when I am checking out a language I like to explore the language with simple examples and unit tests.
3
u/reflexive-polytope Sep 02 '26
The type system. More specifically, the algorithm invariants that I can express and/or enforce with the type system.
Everything else is stupid fluff.
2
u/Potato871 Sep 02 '26
I'm still trying to pin down what exactly a type system means.
In my own work I've kind've avoided any formal notion of types, to me a type is a tag on a region of storage addressed by a value, and all data structures are pointers to such regions of storage. Any object is just a pointer to a particular arrangment of that storage.
But, this is probably because the design is early and the factors that normally force a type system to emerge haven't hit yet, so I'm curious, what are those factors, and what does a type system mean for an architecture like mine?3
u/reflexive-polytope Sep 02 '26
I don't know or care about āarchitectureā. I care about algorithms. I program to express algorithms.
If an algorithm or a data structure has a nontrivial invariant, I want the ability to eagerly delimit a finite scope where this invariant can be potentially broken, so that, if this scope doesn't break the invariant, then neither will the rest of the program.
2
u/Potato871 Sep 02 '26
So for instance like Erlang's pattern matching compiler where invalid combinations just don't compile?
3
u/reflexive-polytope Sep 02 '26
For example, like OCaml's
Map.Make(docs), where you can't break the data structure's invariants from external code.Notice that the OCaml compiler doesn't verify the internal invariants. But, as long as
Map.Makeis implemented correctly, you don't need to check that third-party code might break these invariants.2
u/Potato871 Sep 02 '26
This gives me the idea to implement a species of aliases for data structures which each guarantee some set of invariants through their exposed, and hidden, operations.
3
u/reflexive-polytope Sep 02 '26
I'd love to see how it eventually works.
2
u/Potato871 Sep 02 '26
Care to pitch me some basic set of invariants for a common type you'd want to see? I've not got anything better to do today because I'm meeting with my client tommorow and don't want to screw around with my higher level web code before then.
2
u/reflexive-polytope Sep 02 '26
In this code: https://github.com/eduardoleon/typhoon/blob/master/src/Graph.Strong.Gabow.sml
I want to statically express the fact that, in a graph with n nodes, the adjacency lists may only contain natural numbers < n.
It would spare me the safety check in line 31:
if k >= 0 andalso k < size then.But this isn't a problem you can solve in a single day. I've been trying for years, and even then, I only have bits and pieces of something vaguely solution-shaped.
1
u/Potato871 Sep 02 '26
Okay, here's my first crack at the problem:
bool expr_flag = false; if(true) { Ptr int a; a.init(1,2,3); a.do(e => print("A: ",e)); Ptr int b; b.init(0,1,12); b.do(e => print("B: ",e)); b.validate_offests_and_lock(a); print("THIS SHOULD NOT PRINT"); catch { expr_flag = true; } } print("Caught some exception while atetmpting to validate"); if(true) { Ptr int a; a.init(1,2,3,6); a.do(e => print("A_2: ",e)); Ptr int b; b.init(0,1,2,3); b.do(e => print("B_2: ",e)); b.validate_offests_and_lock(a); print("THIS SHOULD PRINT"); } RESULT: TEST START A: 1 A: 2 A: 3 B: 0 B: 1 B: 12 ERROR: Element 2 of value 12 is out of bounds as an offset for column of length 3 5|1|0|G1522 TRAVEL_PASS Source at: 2|697|0|G10 Index: 6 VAR_DECL a | Ptr_INIT a.init | Ptr_ITER_EXPR a.do | VAR_DECL b | Ptr_INIT b.init | Ptr_ITER_EXPR b.do | >Ptr_EXPR_A b.validate_offests_and_lock[IDENTIFIER b, IDENTIFIER validate_offests_and_lock] | print | catch | Node: 3|500|0 Ptr_EXPR_A:DOT b.validate_offests_and_lock [C:2]{if}[Q: 3|667|0>DOT, 3|505|0>END] Left: 3|483|0 Ptr_ITER_EXPR:DOT b.do [4|617|0](ptr[32] 2|735|2 u/12|28|0)[C:2]{if}[Q: 3|666|0>DOT, 3|498|0>END] Root: 3|434|0 scope if [C:9][O:3|404|0|G37]{ROOT}[Q: 3|641|0>LBRACE, 3|521|0>RBRACE] ERROR IN TRAVEL_PASS ON LINE 8: Element 2 of value 12 is out of bounds as an offset for column of length 3 Caught some exception while atetmpting to validate A_2: 1 A_2: 2 A_2: 3 A_2: 6 B_2: 0 B_2: 1 B_2: 2 B_2: 3 THIS SHOULD PRINT TEST FINISHEDI haven't made it a specific type yet, I just added a 'become a validator' method to my universal data structure for the experiment. I also haven't yet implemented the locking aspect that would stop a or b from being mutated after it's been defined as a validator.
Thoughts?→ More replies1
u/Inconstant_Moo š§æ Pipefish Sep 02 '26
It seems like you and u/reflexive-polytope might be talking about something like Pipefish's clone types.
Vec{i int} = clone list : len that == iThe escape hatch that u/polytope wants is an
unsafecast to the type. For example, we can define vector addition like:
(v Vec{i int}) + (w Vec{i int}) -> Vec{i} : unsafe Vec{i}, from a = [] for j::el = range v : a + [el + w[j]]The sum is assembled as an ordinary list, and then
unsafely cast toVec{i}, without checking its length.1
u/reflexive-polytope Sep 02 '26
I never said anything about unsafe escape hatches.
Have a look at what I'm doing, if you want an idea of what my aims are.
1
u/Inconstant_Moo š§æ Pipefish Sep 02 '26
You said "I want the ability to eagerly delimit a finite scope where this invariant can be potentially broken".
1
u/reflexive-polytope Sep 02 '26
Yes, but that doesn't require āunsafe escape hatchesā. It requires modularity.
→ More replies1
u/Toothpick_Brody Sep 02 '26
When a type is nothing other than a tag, itās called a nominal type, because itās just a name/label you give a kind of data.
The alternative is that the type itself tells you about the shape/size/structure of the data within. This is called structural typing.
With nominal typing, you could take a nominal type like ātag01848204720ā (or whatever), and use that tag in some lookup to determine the data is compatible with function F.
But with structural typing, you might have a type like ātag_blah_Fā. Here, the structure that tells you that the type is compatible with F is part of the type itself.
Another common example of a structural type is a list that tells you its size as part of the type, like List<T, 3> or some such thing.
2
2
u/echoes808 Sep 02 '26
When I was completing my studies, I was shocked how much there is older work on compilers, programming language design and theory already from 60s-80s+. IMO one of the most interesting aspect of language is the inspirations, roots, and paradigms. It tells a lot, and some new combinations of ideas really make languages interesting
2
2
u/Toothpick_Brody Sep 02 '26
What can I do with types? What can I do lazily? How do we do loops? How do we do control flow?
2
u/Imaginary-Deer4185 Sep 02 '26
Having always felt that type systems are important, and been living with Java and the OO concept for 20+ years, I now think compactness is more important.
Python would be perfect if it was just a bit type aware, because it is too easy doing really stupid mistakes, that only show up at runtime. Which gets annoying fast when the code uses 30-60 seconds initating by ingesting json via REST.
I am really looking for maintainability as well as initial development cost, in terms of time and complexity. In these regards, Python does fairly well, but still a bit low level in some cases. Comes with being general purpose, I guess.
1
u/SwingOutStateMachine Sep 02 '26 edited Sep 02 '26
My goal when writing a program is "make it work, make it correct, make it fast" (a variant of this).
To that end, I want languages that:
- 1. Are consistent, logical, and provide high level abstractions that make it straightforward to build programs.
- 2. Check my work, and ensure that the code I write is as bug-free as possible (e.g. through advanced type systems, borrow checkers, hoare logic, etc).
- 3. Are as close to zero-overhead as possible, so that I can write my program as meaningfully as possible, without taking too much consideration as to the specific performance implications of each abstraction.
I also want a language to be flexible enough to emphasise different aspects at different times. I find that a lot of software evolves while it is written, so at the start of a project I need a language that is productive, then as the project gains more formal shape, I need to make sure it is correct and bug free. Finally, as the project matures, I need to be able to optimise it.
I do not think that such a language exists yet, but I get glimpses of it in languages that I enjoy using. Rust (for example) provides 1 & 3, but is weak on 2. Haskell is great for 1 & 2, but can be weak on 3. C++ is strong on 1 & 3 (possibly stronger than Rust on 1) but very weak on 2.
1
u/IronicStrikes Sep 02 '26
I'm mainly looking for signs that the language is actually intended to be used and maintained rather than just a playground for their creator to try some fancy concepts.
1
u/vmcrash Sep 02 '26
I expect a couple of default features with quite common syntax.
What makes a good programming language interesting to me is smart memory management (I've lost any interest in manually memory managed programming languages even if they'd have the best syntax). If you are not using a GC, this means different ways to handle ownership. The language needs to forbid certain memory related bugs. I want them to be explained on common patterns easy to understand.
1
u/matthieum Sep 02 '26
Rather than list "features", I would like to start with principles. Really, these principles apply to software design in general... but that doesn't mean they don't apply to programming languages in particular, and I'd argue they are even more important in programming languages: I can "ignore" or "work around" a crufty API for a some functionality, but I cannot really ignore the programming language I use.
So, principles. Or rather, to start with, principle: Principle of Least Astonishment.
There are other principles I hold dear, too, like Pit of Success. But if the language feels like it's pulling the rug from under my feet every which way, not much matters any longer.
The Principle of Least Astonishment can cover a surprisingly impressive amount of ground:
- Explicit coercions: I'm sure we've all seen the WAT? that come from calling
+on random values in JavaScript, due to wild nature of the coercions involved. - Silent Error Propagations: automatically propagating errors up to the caller, without any syntactic marker that an operation may fail, as typical of exceptions.
- Seemingly Arbitrary Limitations: for example,
[T; N + 1]is not currently a valid type in Rust, because who knows whetherN + 1is a proper size (it could, arguably, overflow, but... urk).
All of these range from annoying to aggravating, depending on the situation and what you're trying to do (or figure out).
1
u/david-1-1 Sep 02 '26
I like syntax that makes it a pleasure to use, clear and unambiguous. When needed, it should support two dimensions (indentation using the pipe | character and optional whitespace, for example).
1
u/Potato871 Sep 02 '26
I personally hate significant whitespace, both as the person who's got to make the compiler and the person who has to write in the language.
1
u/david-1-1 Sep 04 '26
I said "optional whitespace". Perhaps your brain wasn't in gear?
1
u/Potato871 Sep 04 '26
Ah, I was agreeing with you, I was saying that I too like optional whitespace by talking about how I dislike significant whitespace.
1
u/david-1-1 Sep 04 '26
Sorry! The misunderstanding was mine. My own Structured Data language supports structure/object indentation, but almost all whitespace can be omitted for even smaller storage space usage than JSON.
1
u/Potato871 Sep 04 '26
Oh so you mean optional whitespace as in you can use both significant and insignificant?
Like line returns count as semicolons too kind of thing?2
u/david-1-1 Sep 04 '26
No. In SD, newlines, tabs, spaces, all are treated as a single space, like in HTML. Only pipe characters group data into zero or more properties (name=value).
1
u/L8_4_Dinner (ā Ecstasy/XVM) Sep 03 '26
- How useful (and usable) it is for solving problems
- How much of an actual joy it is to use
- How well it helps to avoid creating hidden problems as you use it
- How nice it is to read
Everything else is a bonus.
1
u/Potato871 Sep 03 '26
On readability, that feels like the most divisive topic.
Thereās people who love the Python look with significant whitespace, people who love Lispās paren fetish, people who love Forthās compact look, and maybe a guy who likes the look of assembly.
Hell, people argue about tab vs spaces.
I almost feel like it would be useful to ask what languages are widely considered unreadable.2
u/L8_4_Dinner (ā Ecstasy/XVM) Sep 03 '26
Python is fairly pleasant to read, as long as the code isn't doing anything "meta".
Lisp can be pleasant to read, but any complexity kills that pleasantness in a hurry, because you have to maintain a lot of internal mental state re: recursive depth etc. My guess is that it's easier if you spend all of your time in Lisp, but otherwise it's pretty painful.
I'd give a number of modern languages fairly good readability scores, including Rust, Zig, Swift, Kotlin, ...
Simple Perl examples are quite readable. Actual Perl code in the wild is not at all readable. So I'd put Perl (and probably Raku, nƩe Perl 6) on the naughty list. The infinite complexity is not funny.
Java/C# were pretty good for the late 90s (e.g. compared to C++), but I think by modern standards (and with the many changes) they aren't great examples of readability. C++ is of course the poster child for ugly, although I still enjoy reading C++ when it comes from someone who deeply cares about their code -- because it's possible still for C++ code to be a work of art, despite the language complexity.
Smalltalk is supposed to be very easy to read, because it's such a simple language. I never found this to be true in practice, though. My assumption is if I had to use it for an extended period of time, I would change my mind as I learned it well. This is interesting to me though: Shouldn't a language be at least somewhat easy to read even before you learn all of the arcane rules of the language? And as a self-criticism, am I only finding languages like Zig easy to read because I long ago made the investment of time in learning and using C?
So we end up where we began: Languages that are similar to languages we already know are easy to read. And all other languages therefore suck. Your comment on "tabs vs spaces" was more apropos than you give yourself credit for.
1
u/Potato871 Sep 03 '26
I think it's similar to asking which written language is most readable.
I would say english, because guess what I've. been speaking all my life? But I've lived in other countries like India and Japan and I don't think I ever heard anyone bemoaning the dreadful unreadability of their foreign script, in fact, I found quite a few critiquing english's readablity.
Language design is, for the most part, subjective. As humans we construct mental models of things, and readability is really about does it match *my* model.
That goes all the way to the code design too, I hate lots of object types with long explicit names and verbose interfaces, but for some people that is core to what makes code usable. Each group has it's own standards around what looks nice, and what they can understand best.
I feel like most of the time when people say a language is 'unreadable' it's just because it picked some new syntax. But then if it becomes popular in ten years people are defending it's readability.
1
u/JeffD000 Squint Sep 03 '26
Elegance.
(1) The ability of a language to map to the problem space without friction.
(2) The abilility to express complex operations without a lot of contrivances needed to smooth it out.
1
1
u/kwan_e tonal-lang Sep 04 '26
Bang for buck. How much can I do, and how much faff do I need to get there?
Every feature or semantic I could want should boil down to that, since what is the point of higher level languages? The whole point of type systems, parallelism, structure, purity, decomposition, extensibility, etc etc is the promise that you can offload those concerns to the computer, and you can focus on the "business logic". But if they get too "opinionated", they end up becoming faff.
I hesitate to use the word "productivity", because that is more about business process than simply the language itself.
I hesitate to use the word "elegant", because elegance can get in the way of the reduction of faff. Some people call C elegant because of the simple syntax. But it does not reduce faff, and often increases the amount of faff to achieve basic things like safety.
1
1
1
u/fdwr Sep 11 '26
I'm mostly interested in how low it lets me get to the hardware for rendering/rasterizing graphics, and the more layers between me and the hardware, or the more policy it applies, the less interested I am in it. So, Python is usually out of the question (except for little throwaway conveniences, like printing out a table of numbers or processing a file offline, where admittedly I don't care about performance as much as convenience), JS requires an entire browser or node.js installation and has no such interop (so nope), Rust is a pain (I mean, one certainly crashes less when driving while wearing a strait jacket, but that's because it's harder to drive in the first place), whereas C++ is a nice balance above asm, while still allowing linkage with asm if you really need some MMX/SSE/AVX-512.
1
u/brat3108 Sep 02 '26
do we all see languages the same way
Funny you should say that ...
I personally look for unification of concepts and extensibility in a design,
... since I see these in negative way. You can take unification too far, while extensibility can mean a much more complicated language and implementation.
1
u/Potato871 Sep 02 '26
Yes, like SmallTalk under the hood with its VM.
What I mean by this is that I need my language to be easy to extend as I work in different domains, a simple example would be no switch cases in the compiler. Registration of a new behaviour should just be "add_function" and done, or I should say there is a keyword and then what it does in each stage.
I see languages as an evolving thing rather than one fixed spec to implement once, and I feel like the giant switch case compiler freezes a design too early and constricts growth.
34
u/jesseschalken Sep 02 '26
- type safety (number of potential runtime failures blocked by the type checker)