/r/ProgrammingLanguages

Photograph via snooOG

This subreddit is dedicated to the theory, design and implementation of programming languages.

Welcome!

This subreddit is dedicated to the theory, design and implementation of programming languages.

Be nice to each other. Flame wars and rants are not welcomed. Please also put some effort into your post, this isn't Quora.

This subreddit is not the right place to ask questions such as "What language should I use for X", "what language should I learn", "what's your favourite language" and similar questions. Such questions should be posted in /r/AskProgramming or /r/LearnProgramming. It's also not the place for questions one can trivially answer by spending a few minutes using a search engine, such as questions like "What is a monad?".

Related subreddits

Related online communities

/r/ProgrammingLanguages

104,291 Subscribers

4

Pipefish-Golang interop; and can I glue all the languages?

With some recent improvements the way Pipefish does Golang interop has gone from a shameful hack with limited features to a little technical gem that does everything.

How it works from the user end is nice and simple. You can write the signature of a function in Pipefish, and the body in Go, joined by the golang keyword as a Pipefish-to-Go converter:

fib(n int) : golang {
    a := 0
    b := 1
    for i := 0; i <= n; i++ {
        a, b = b, a + b
    }
    return a
}

This gives access to the extra speed of Go, and makes it trivial or indeed automatable to turn Pipefish libraries into standard libraries.

To make this nice for everyone we have interop on the type level: we can pass around all the basic types; all the container types (lists, maps, sets, pairs), and lambdas. (The lambdas aren't just to show off, the Go people are into libraries with functions that take functions as arguments. So passing them is important. Returning them was to show off, I can't think why anyone would want to.)

And then the user-defined types in the Pipefish code are known to any Go function that needs to know about them:

newtype

Dragon = struct(name string, color Color, temperature Temperature)
Color = enum RED, GREEN, GOLD, BLACK
Temperature = clone int

def

// Returns the color of the hottest dragon.
dragonFight(x, y Dragon) -> Color : golang {
    if x.Temperature >= y.Temperature {
	    return x.Color
    }
    return y.Color
}

All this "just works" from the POV of the user.

How it works on the inside

This time I thought I'd give the technical details because the other Gophers would want to see. I think the only thing that could be significantly better than this is if using the plugin package at all is a local optimum and there's an overall better architecture in which case let me know. (Please, urgently.)

Go has a plugin package. The way it works is in principle very simple. You tell the Go compiler to compile your code into a .so file rather than an ordinary executable. You can then point the plugin package at the .so file and slurp out any public function (by name) into a Value type which you can then cast to a function type:

plugin, _ := plugin.Open("plugin_name.so")
fooValue, _ := p.Lookup("Foo")
myFooFunction := fooValue.(func(x troz) zort)

myFooFunction now does the same as Foo, and as I understand it, does so without overhead, it just is the original function.

(In practice this is rickety as heck and also Google hasn't bothered to spend any of their vast cash on making this supposedly "standard" library work for the Windows version of Go. The discussion on why not includes the comment that it is "mostly a tech demo that for some unholy reason got released as a stable feature of the language". I can't do anything about any of this except maybe send roadkill through the mail to all concerned. However, when using the plugin package I have learned to turn around three times and spit before invoking the juju and it's working out for me.)

Sooo ... all we have to do is take the embedded Go out of the Pipefish script, compile it, and it should run, and then we slurp the Go function out of the plugin, tell the compiler to wrap the Pipefish signatures around it, and Bob's your uncle, right?

Well, not quite. Because for one thing, all the embedded Go is in the bodies of the functions. The signatures are in Pipefish:

// Returns the color of the hottest dragon.
dragonFight(x, y Dragon) -> Color : golang {
    if x.Temperature >= y.Temperature {
	    return x.Color
    }
    return y.Color
}

So we need to translate the signature into Go. No problem:

func DragonFight(x Dragon, y Dragon) Color {
    if x.Temperature >= y.Temperature {
        return x.Color
    }
    return y.Color
}

And of course we're going to have to generate some type declarations. Also easy:

type Temperature int

type Dragon struct {
    Name string
    Color Color
    Temperature Temperature
}

type Color int

const (
    RED Color = iota
    GREEN
    GOLD
    BLACK
)

Now our generated code knows about the types. But our runtime doesn't. So what we do is generate code defining a couple of variables:

var PIPEFISH_FUNCTION_CONVERTER = map[string](func(t uint32, v any) any){
    "Dragon": func(t uint32, v any) any {return Dragon{v.([]any)[0].(string), v.([]any)[1].(Color), v.([]any)[2].(Temperature)}},
    "Color": func(t uint32, v any) any {return Color(v.(int))},
    "Temperature": func(t uint32, v any) any {return Temperature(v.(int))},
}

var PIPEFISH_VALUE_CONVERTER = map[string]any{
    "Color": (*Color)(nil),
    "Temperature": (*Temperature)(nil),
    "Dragon": (*Dragon)(nil),
}

Then the Pipefish compiler slurps these in along with the functions, turns them into (a) a map from Pipefish type numbers to the functions (b) a map from Go types to Pipefish type numbers, and stores this data in the VM. This provides it with all the information it needs to translate types.

  • This bit extracts the data from the .so file and does housekeeping.
  • This bit generates the .go source file.
  • This bit does the type conversion for the VM at runtime.
  • And this is the place in the VM that calls the Go function.

Can I glue all the languages?

Rust, for example, is a nice language. Can I glue it into Pipefish in the same way?

In principle, yes. All I have to do is make the compiler recognize things that say rust { like it now does things that say golang {, and write a thing to generate Rust code and compile it, and then another thing to generate a Go plugin that knows how to do FFI with the compiled Rust. Simple. Ish. Of course, there are lots of languages, many of which I don't know (Rust, for example) and so working my way through them all would not be a good use of my time.

However. Suppose I make a languages folder in the Pipefish app that people can drop .go files into. For example rust.go. These files would be converted into .so files by the Pipefish compiler (people can't just supply ready-compiled .so files themselves because of version compatibility nonsense) Each such file would contain a standardized set of functions saying how to generate the source code for the target language, how to make object code from the source code, and how to write a .go file that compiles into a .so file that can do FFI with the object code in the target language.

So then anyone who wanted to could write a plugin to add another language you could glue into your Pipefish code.

I don't see why it wouldn't work. Perhaps I'm missing something but it seems like it would.

0 Comments
2024/12/01
14:48 UTC

26

Chaining comparison operators

In Miranda, comparison operators can be chained, e.g.

if 0 <= x < 10

desugars in the parser to

if 0 <= x & x < 10

This extends to any length for any comparison operator producing a Bool:

a == b == c < d

is

a == b & b == c & c < d

I like this, as it more closely represents mathematical notation. Are there other programming languages that have this feature?

https://en.wikipedia.org/wiki/Miranda_(programming_language)

40 Comments
2024/12/01
13:49 UTC

1

Could a higher-level Rust-like language do without immutable references?

Hi everyone. I've recently contemplated the design of a minimalist, higher level Rust-like programming language with the following properties:

  • Everything has mutable value semantics, and local variables/function arguments are mutable as well. There are no global variables.
  • Like Rust, we allow copyable and move-only types, however copyable is the default, while move-only is opt-in and only used for types representing non-memory-resources/handles and expensive-to-copy (array-based) data structures. Built-in types, including strings, are copyable.
  • Memory management is automatic, using inplace allocation where possible, and implicit, transparent heap-allocation where necessary (unsized/recursive types), with copy-on-write for copyable types. We are ok with this performance vs simplicity-tradeoff.
  • References might use a simpler, but also less flexible, by-ref model, with usage of references as fields being more restricted. Sharing and exclusiveness of references would still be enforced as it is in Rust, since it makes compile-time provable safe concurrency possible.

Clearly, mutable value semantics requires some way to pass/return-by-reference. There are two possibilities:

  • Provide both immutable and mutable references, like in Rust or C++
  • Provide only mutable references, and use pass-by-value everywhere else

With most types in your program being comparably cheap to copy, making a copy rather then using an immutable reference would often simpler and easier to use. However, immutable references still come in handy when dealing with move-only types, especially since putting such types inside containers also infects that container to be move-only, requiring all container types to deal with move-onlyness:

  • Queries like len or is_empty on a container type need to use a reference, since we don't want the container to be consumed if it contains a move-only type. Being forced to use an exclusive mutable reference here may pose a problem at the usage site (but maybe it would not be a big deal in practice?)
  • Iterators would need to return map keys by immutable reference to avoid them being moved or changed. With only mutable references we would open ourselves up to problems arising from accidentally changing a map key through the reference. However, we could also solve the problem by only allowing copyable types as map keys, and have the iterator return keys by value (copy).

What do you think about having only exclusive mutable references in such a language? What other problems could this cause? Which commonly used programming patterns might be rendered harder or even impossible?

1 Comment
2024/12/01
10:24 UTC

1

The case for subtyping

Subtyping is something we are used to in the real world. Can we copy our real world subtyping to our programming languages? Yes (with a bit of fiddling): https://wombatlang.blogspot.com/2024/11/the-case-for-subtypes-real-world-and.html.

6 Comments
2024/12/01
03:15 UTC

19

December 2024 monthly "What are you working on?" thread

How much progress have you made since last time? What new ideas have you stumbled upon, what old ideas have you abandoned? What new projects have you started? What are you working on?

Once again, feel free to share anything you've been working on, old or new, simple or complex, tiny or huge, whether you want to share and discuss it, or simply brag about it - or just about anything you feel like sharing!

The monthly thread is the place for you to engage /r/ProgrammingLanguages on things that you might not have wanted to put up a post for - progress, ideas, maybe even a slick new chair you built in your garage. Share your projects and thoughts on other redditors' ideas, and most importantly, have a great and productive month!

38 Comments
2024/12/01
00:01 UTC

0

Neit: This time a proper lexer , parser and codegen

https://reddit.com/link/1h3fpg5/video/e1610wr9b24e1/player

the source code can be found at : https://github.com/oxumlabs/neit

update -> many new things have been added to lang which am not able to show here i woudl recommend you checking out the website to get full details (please note the site isnt the best and still needs improvemnts):
https://oxumlabs.github.io/nsite

9 Comments
2024/11/30
16:05 UTC

9

Examples of languages with "spreading return type"

I am thinking about a concept where it would be possible for a function to declare its return type to be automatically spread into its caller's scope upon return.

So that one could write a function which returns "...{a: number, b: number}"

A call to this function would then either return the object or void, but would insert "a" and "b" into the caller's scope.

Are there languages with support for this that I could look at for inspiration?

46 Comments
2024/11/30
01:56 UTC

46

Dart?

Never really paid much attention to Dart but recently checked in on it. The language is actually very nice. Has first class support for mixins, is like a sound, statically typed JS with pattern matching and more. It's a shame is tied mainly to Flutter. It can compile to machine code and performs in the range of Node or JVM. Any discussion about the features of the language or Dart in general welcome.

29 Comments
2024/11/28
22:02 UTC

0

Auto delete variable - opinion

I'm thinking of adding a auto deletion for variable creation in my language, so you could say that it should be deleted after x retrievals or x seconds

The idea comes after I noticed that I had a private key that was read from a file while debugging, long after it being used

I was wondering if you guys have any option on this.

Here is a example of how it would look

- read private_key.txt into %key%, delete after 1st usage
// Use %key% variable
// %key% is no longer in memory

So now the line that creates the %key% variable is responsible for how it is deleted and I don't need to set it as null later

7 Comments
2024/11/28
16:34 UTC

18

Should I include type info on my AST on the first pass?

I'm starting to build my AST and have been keeping type information as a string. However, for array and dictionary literals, the type info is starting to get more complex. Should I include type information on my AST on the first pass, or is that something I should worry about later?

Right now I could create a string representation for an array of basic types e.g. `typeInfo="[int]"` or something similar, but an array of functions would get more complex especially if type inference is needed e.g. `typeInfo="[func(Int)Int]"` ?. Stringifying the type info immediately looks like a bad idea, so it seems a proper `TypeInfo` interface/struct is needed, but I'm wondering if I need to gather some information on the first pass and refine it later or completely deal with in later on a second pass or even maybe during the semantic analysis and remove the type info for now?

19 Comments
2024/11/28
14:01 UTC

5

How Designing Carbon C++ Interop Taught me About C++ Variadics & Bound Members - Chandler Carruth

2 Comments
2024/11/26
03:00 UTC

16

Help finding website with many programming languages grammar to download

I found a very long time ago a website where you could download a grammar file from many programming languages, I remember to download there the VBScript language grammar definition.

If I am not mistaken, this website was part of a Windows software made to develop programming languages. Can you help me find this website?

6 Comments
2024/11/25
16:21 UTC

22

What makes ui frontend language design hard? (Asking for help). First time to try to build one.

I’ve tried a lot of frontend languages/frameworks: react js ts elm purescript svelte etc. but at some point i have no idea what i’m looking at. I could just be bad at coding, but when i look at projects github by nice people, i have to read a while before i understand what is happening and even then, when i read the code, i can only vaguely tell you what it is going to look like (except when they use a well known library without modification).

Back in html/css heavy pages with little javascript. I feel like it is easier to visualize what the thing will look like if i have the html and css side by side.

Then there is the concept of how coupled is semnatics with the design.

A lot of frameworks and languages have been made and so far i feel the main components they differ:

  • state management
  • syntax
  • coupling: is structure closely tied to function and design

It would be my first time designing and implementing a language and i want it to transpile to html/css/javascript. I want to go about it from the ui-perspective. But i don’t really know what i’m saying, so i’m coming here for help and clarity.

What questions should i be asking? Is state management the hardest aspect? Merging markup-like with template-like syntax can be confusing to me (why use jsx if i can do functions directly? That’s a personal opinion maybe).

Thanks!

11 Comments
2024/11/25
11:17 UTC

5

Default declare + keyword for global assign ?

(Edit for clarity)

My lang has a normal syntax :

var i:int = 1   // decl
i:int = 1    // decl
i:int    // decl
i = 2    // assign

Scoping is normal, with shadowing.

Now, since most statements are declarations and I am manic about conciseness, I considered the walrus operator (like in Go) :

i := 1    // decl

But what if we went further and used (like Python)

i = 1    // decl !

Now the big question : how to differentiate this from an assignment ? Python solves this with 'global' :

g = 0
def foo():
    global g
    v = 1 // local decl !
    g = 1 // assign
 

But I find it a bit cumbersome. You have to copy the var name into the global list, thus changing its name involves 2 spots.

So my idea is to mark global assignments with 'set' :

var g = 0
fun foo() {
    v = 1     // decl !
    set g = 1 // assign
}

You'd only use SET when you need to assign to a non-local. Otherwise you'd use classic assign x = val.

{
    v = 1     // decl 
    v = 2    // assign
}

Pros : beyond max conciseness of the most frequent type of statement (declaration), you get a fast visual clue that you are affecting non-locally hence your function is impure.

Wonder what you think of it ?

43 Comments
2024/11/24
21:14 UTC

23

How to implement rust like enums?

I'm newer to rust, and using enums is a delight. I like being able to attach data to my enums, but how would this be implemented under the hood? I'm looking into adding this to my language, Luz

14 Comments
2024/11/24
00:53 UTC

Back To Top