Yuck. I like both Go and C# a lot, and use them both professionally.
In my experience the strengths of Go are mostly
- Deployability via single-file static binaries
- Simple syntax that anyone can learn (no exceptions, no classes or inheritance)
- Wicked fast compile times
And the strengths of C# are
- Powerful language with null-safety and lots of syntax sugar
- Runtime-level coroutines so you don't need `async/await` everywhere
G# seems like it has the _worst_ of both worlds, not the best. It's fun to write compilers, and good on them for doing it, but no thank you for real use
Exactly. To add to this, is called ahead-of-time compilation, and bundles required parts of the .net runtime into the single-binary. Deployment targets thus don't need to ship any .net environment or libraries.
AOT is entirely independent of single file binaries. And self-contained binaries that run without the framework installed are again a separate concept. There are some dependencies between these, but they are not the same thing.
AOT is not all that useful yet for many applications as important libraries still don't support it. So more something for things like CLI tools with a small scope.
It's not quite the same as with Go, the binaries get large if you can't trim them. But creating single-file self-contained executables is very much usable and works well otherwise.
> AOT is entirely independent of single file binaries.
splitting hairs, but its is not independent. AoT is a required pre-requisite for single-binary creation. You can't create single-binaries with JIT. And that is the big hurdle, lot of libraries do not support AoT and that is the blocker to create single-file binary. Once you have the AoT figured out, the single-binary creation is easy.
Yes, you can. I am using that in production right now. An ASP.NET Core application as a self-contained single-file binary, without AOT.
.NET AOT right now is a very specialized solution that isn't widely applicable. Self-contained and single-file binaries do work pretty much out of the box already.
See the documention here for the PublishSingleFile and SelfContained options:
Yes but no. It's essentially a self-extracting executable, so adds significant start-up time. It also doesn't work in all cases, for example the database driver files to the DB we use aren't compatible with the single-file deployment method.
C# is a pretty bad language when you take away the stack it sits atop of. I do mostly like the async but developers put up with a lot of shit to e.g. use the msft networking stack and containers
I feel the opposite. It is one of the genuinely competent languages out there, if you're the kind of person that isn't upset about it being a "kitchen sink". Instead, I feel like the ecosystem, community and reputation hold it back. There are nowhere as many useful and popular packages to reach for as Python for example. Unity3D always lags behind in runtime and language version and had amazingly bad package management -- this further hamstrung C#, because the language is never used in a vacuum.
It's a product of an era of OOP when the idea of a program fitting in a developers head was a dangerous reactionary idea.
They have in fairness fixed a lot of the worst aspects of this by adding basically a second language to it but e.g. I massively prefer writing F# if purely because if I want to do something I can just to it rather than first implementing public static DoThing : IDoThing
I've worked with C# for a decade, and Go for the past 5ish years and I think the biggest difference between them is in the philosophical design on implicity and explicity. I have a strong dislike for C# like languages these days, but it's not for technical reasons. I think C# is supperior to Go in many ways, but I absolutely hate the implicity in it's design, and this is a personal opinion that is not objective. In this context I can't imagine how you would create a mix of the two that wouldn't violate either approach. Looking at something like this:
I would argue that they made something I suspect many Go developers will dislike. I know I absolutely hate it. If I wanted to do things like that I might as well use C#. Then again, these days I'm shifting more and more of my development to either Python (which is objectively an awesome language that also sucks) or Rust. While one of my favorite features of any programming language is the Go modules with single folders and upper and lower cases for private/public. I am becoming a fan of how rust does structs with impl methods.
How is this different than C#? What new concepts does this bring that C# doesn't?
20 years ago there was some momentum behind Visual Basic .Net; but the language was so similar to C# that it just wasn't worth using. There was a joke that .Net was a "skinnable language."
BTW, there's a whole nitpicky/semantic argument that C# isn't null safe because of the null forgiving operator. That will probably come into play with G# if the null forgiving operator can be used from C# to pass null into G# code that doesn't expect it.
There was a joke that .Net was a "skinnable language."
I remember the MS documentation had sample code in all the variants of .NET languages they created (C#, F#, VB.NET), and of course there were decompilers that let you choose which one to target, with many other translation tools available between them.
I wish README is clear whether they are using AI or not, and if so what the guidelines are. Not that anything wrong with using it, but given anyone with $$$ for tokens can do it, its nice to know what their process is etc etc. Gives me more confidence that its worth checking out.
If you look at the list of contributors, you see Claude and Copilot, but on the other hand, You can see a huge, functional codebase going back to as far as 2024, so its safe to say its not vibecoded.
This should be a standard section in READMEs now. I've started adding it to mine. Even if you don't use AI, please add a section saying that! It can be one sentence.
# Use of AI
No AI was used. / This is entirely written by Claude and I didn't even read the code. / ...
So... the verbosity of Go without the compile speed of Go? Go is not a language I would associate with ergonomics, and this doesn't even have most of modern C#'s best features: does xUnit.NET work? Does immutable records work? Do collection expressions work? Does LINQ work?
Calling a language with `let` instead of `const` and async/await and iterators and classes "Go" is plain just incorrect. This G# is more similar to TypeScript than Go.
The ONE feature that C# really needs is payload enums with `match` instead of C#'s current pattern matching with `switch` anyways, and Rust is more similar to Go anyways so why not copy from Rust instead? I'm honestly baffled.
I don't find Go especially verbose - in fact, due to the economy of syntax, Go code without the usual syntax sugar features ends up similar in length to other curly brace languages. I tested this with C# and Typescript, where I migrated projects from these languages to Go - the overall volume of code stayed roughly the same.
Not horrible imo. But I've found that verbose error handling and explicit errors made me consider which parts of the code can return err, and reorganize code around that - with that I've been able to eliminate most 'err' from my codebase.
Like, if you go by function: ReadData(has err)-> ParseData(has err) -> ProcessData(no err)
Instead of having functions that can fail dynamically all over your codebase.
Yeah, I still don't understand why they don't just use enums and have to invent a special "union" keyword instead. C#'s enums are extremely underpowered to begin with and the syntax they designed here way more convoluted and uglier to say:
enum Pet {
Cat,
Dog,
Bird
}
var description = Pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
_ => "no pet"
}
The other issue is they introduced `null` to pattern matching on their union example when the whole point of pattern matching is that you can pretty much mostly remove `null` from the language altogether with Result<T, E> available, as Rust has shown.
It sounds like they didn't reuse the enum keyword for this for the most backwards compatibility and to avoid confusion. Your example enum is an `int` today. Either you break existing code expecting an `int` sized thing or you need additional syntax and can't use the "clean" form that you are hoping for.
The null patterns predate these unions and the relevant section of the documentation is showing that you can use nullable unions, not that you have to or should use them. Other examples also show a fully closed Result<T, E> type that yeah would be great for projects hoping to eliminate more nullable code.
- stupid question: how do you make a programming language like this from scratch?
- what is the thought process that goes into making a programming language
- what is this field of study or discipline called?
- why do we have so many programming languages? what purpose do they intend to solve and how do we know what purpose a programming language was made for?
- for example, why was swift made if objective c exists and why was objective c made if c++ exists?
> how do you make a programming language like this from scratch?
Write a parser from your language’s syntax to an AST (Abstract Syntax Tree) which is the representation of the code in memory. Now write a function from the AST to the compiler output format. That can be some executable binary format (see https://en.wikipedia.org/wiki/Comparison_of_executable_file_...) or some other language, like C (a common target) or something made exactly for that like LLVM (used by clang and Rust), Java or C# bytecode if you don’t mind requiring a VM to run the application. I’ve written Java bytecode generators and it’s surprisingly easy! Getting a simple language off the ground is a lot of fun and not a huge challenge.
When I was in university the course was called compiler construction. Making a language like G# is very simple and about the level that the final project of the course would be if the team was working together really well and went for maximum bonus points.
We have so many programming languages because it's a fun and relatively easy thing to start, and lots of people have differing opinions of how it should be done. Also making a programming language seems like a difficult thing from the outside so it has a certain allure.
Swift exists because objective c has archaic language design that modern developers reject. Objective C exists because as far as I know at the time smalltalk style object oriented programming was hip and C++ made the wrong decisions in their eyes. It could also be that C++ wasn't popular enough yet at that point for Apple to commit to it. In that period basically all major operating systems went different ways. The Unix derivatives went all in on plain C, Microsoft went C++ and Apple objective c, though I think OSX itself is plain C for the most part.
Making new programming languages is something a lot of people do for fun, and it's also covered in most CS degrees too, albeit briefly.
We have so many programming languages because they tend to have a particular niche in which they're useful. Many languages are still in use even though they're very old (C, FORTRAN, COBOL), and others just keep getting updated over time and have a large userbase (Java, Perl, Ruby, Python).
99.99% of all new programming languages never get a critical mass of users. People create a new language to learn something, and they're the only user. e.g. I've written a few FORTHs, have spent the past few weeks on writing a lisp compiler, and in the past wrote BASIC interpeters for fun.
If you want to make your own "crafting interpreters" is a good read:
But there are a million other tutorials on writing a simple lexer/parser/interpreter/compiler, and a lot of academic literature (e.g. The Dragon Book).
- it's easy to prompt an LLM to do it for you, especially if you're targeting a pre-existing runtime like CLR or transpiling to another language. previously you'd have to grind out the parser and compiler for a new language, but a lot of that work is mechanical
- "I want a language that works a little differently"
- programming language theory (PLT), generally
- languages are tools. the authors should explain what their languages are best suited for
- Obj C and C++ were both developed around the same time as extensions of C. Obj C was focused on message passing and Smalltalk's object system, while C++ was focused on adding as many abstractions as possible to C. Neither language has good support for avoiding null pointer dereferences, one of the primary things Swift addresses with its richer type system and Optionals.
For your first two questions, I can't recommend Crafting Interpreters enough, it's probably one of the best entry-level books that goes into that entire process.
i have made a language that xompiles to c#. I wrote a lexer. then a parser. then a type checker (hindley milner, function local so that top level functions must have type signatures) a match compiler.
the hardest part was what came next: the code generation. despite producing c# instead of MSIL. The features I use are: static and dynamic traits, pattern matching, and a concurrentML.
It is actually quite simple when you don't have to do closure conversion yourself.
I've done that for transpilation from SAOL (an MPEG 4 historically curious language) to C++. It does make it incredibly easy to write the compiler.
The big drawback that I never managed to sort out is how to integrate with visual debuggers. How to generate GDB source mappings (or .PDB source mappings) that reference the original LanguageX source files.
So you end up with a toy language that is un-debuggable. Which is not nearly as much fun as it should be.
Just trying to offer some help here, not an attack:
```
G# brings Go-, Kotlin-, and Swift-style ergonomics — packages, func, data class, nullable handling with if let, structured concurrency with scope — to the .NET runtime. Source compiles directly to managed assemblies.
```
This is a decent description - but as someone also building a language in a similar space - who isn't super familiar with the .NET runtime... My first question is... Why not C#?
I'm by no means a C# expert, but I thought most of this was supposed to be in C#. C# is not terribly un-ergonomic, and Go is simple, but not really ergonomic except for Goroutines...
`packages` and `func` being the first two selling points is alarming. Sure, people probably prefer `fn foo() -> Dog` over `Dog foo()`. No one's picking a language for that. C# has namespaces... C# has `record` and `record struct`. C# has not-ideal nil handling, but it still has it. I'm not convinced `if let` is better enough to be a selling point - a lot of people don't like that!
Your main selling point seems like `scope` and your concurrency model vs C#, but C#'s is not exactly terrible...
Rich Hickey has a joke about semi-colons in language design, and your main pitch seems to sell yourself short.
Btw, I think your GitHub page does your language a lot better justice.
"I'm already quite sure how I will die: I'll read another article on Hacker News about a new programming language where I see nothing new, and I'll read that they included {}; to make C programmers comfortable. I'll have a massive stroke."
It’s probably too little too late in the age of Claude…
C# grew all those features over time. It had to leave syntax to support old patterns to preserve backwards compatibility. Thus, the syntax has grown a bit noisy over time to support all those features. This is reboot keeping the newer ergonomics and streamlining the syntax.
I probably wouldn’t adopt it for existing projects or use .Net for any future project, but it looks really nice for what it is.
I used it recently to write a useful utility related to OpenTelemetry file processing. .NET AOT produced a single-file static binary which is similar in size to what Go would produce, and can be dropped into any target system and run without dependencies, just like Go does.
Reflection, is one thing. Of course some runtime stuff are missing, but the problem is that no one is using source generators before trying out aot, so as soon you try aot you just meet a wall of compilation errors. Most people just want to be able parse a json file without jumping through hoops. Bad DX
The JSON source generators are quite good, and a small performance boost worth considering even when not planning for AOT. The logging and RegEx source generators aren't even for AOT but for improving debugging tools [1] and performance.
Everyone should be exploring source generators already whether or not they expect to try out AOT.
[1] Debugging source generated RegExes is a dream, including being able to breakpoint inside a RegEx in the .g.cs file should you need to trying to get a tricky RegEx right. The code generated by the RegEx Source Generator is incredibly readable and includes great comments that explain what the RegEx does, step by step. Those comments show up as documentation comments on the partial .cs file side once the file is generated and can be used to double check that the RegEx you wrote matches what you expect it to do as you write/update the RegEx and the source gets regenerated (which happens pretty fast).
It works through the new UnsafeAccessorAttribute [1]. This provides the information needed for AOT to know what needs to be in the final binary and not trimmed. It also removes the lookup overhead associated with normal reflection which is very nice.
> Plain old reflection that just works (why should it not?)
I definitely don't fully understand the landscape, so I could certainly be wrong, but I assumed that normal reflection didn't work in AOT because after trimming that method may or may not be there. If it was never called in a normal way then the compiler doesn't know that `Console.WriteLine` was being used as `GetMethod` may have a runtime value as a string rather than a constant value known at compile time. If the compiler didn't know it was being called then it will be trimmed out of the final binary whereas with `UnsafeAccessorAttribute` it provides the information required to not trim it.
Edit: I tried the following https://sharplab.io/#v2:D4AQTAjAsAUCAMACEEB0AlApgMwDaYGMAXAS... and it fails when I provide the type and method for Console.WriteLine as arguments. If I was to add `typeof(Console).GetMethod(args[1], [typeof(string)])!.Invoke(null, ["dummy"]);` to it before the `Type.GetType` call it seems to be enough to not trim out the `Console` type and the `WriteLine` method. The compiler seems to at least be smart that way.
It is not so dishonest, and you explicity added the small "ootb" to your statement. That is the point, out-of-the-box it might not work and you will have to do some refactorings, but if you start a new project with AoT you will keep it in mind.
why doesn't anyone just jump the gun and introduce proper parallelism primitives? SML/NJ got it right in 1991. ocaml5.0 has domains and effect handlers.
why do people still accept CSP? It is simple to do some things in it, bit please just give me concurrentML with "simple" channels for that kind of work , and proper channels for any kind of hard stuff. I have had to write things in go that took me days to get straight that would have been 20 trivial lines in any concurrentML implementation.
Potentially viewable as better than OpenJDK and Oracle (and OracleJDK) from what I've seen. A lot of .NET governance moved to the Dotnet Foundation which is built along the lines of things like the Linux Foundation. Microsoft is the major contributor to .NET and a major sponsor of the Dotnet Foundation, but most of their contributions are still flow through the Foundation legal/governance structure and subject to the same governance as anyone else today. .NET is almost entirely planned and developed openly on GitHub including things like meeting minutes for all in person meetings.
I feel like we've done full circle. Languages are back to being (mostly) procedural. I'm not sure I like it, but it seems that this is what people prefer.
Personally, I'd rather see something like dependant types on a dotnet language. An addition, not just a simplification.
> I feel like we've done full circle. Languages are back to being (mostly) procedural. I'm not sure I like it, but it seems that this is what people prefer.
Is this an actual shift, or is this just what happens when LLMs make it possible for anyone to build a language quickly?
This one feels less like someone thought carefully about what semantics they wanted to have and more like someone without a lot of familiarity with the design space of programming languages decided to build one that had all their favorite features from the languages that they already know:
> G# brings Go-, Kotlin-, and Swift-style ergonomics — packages, func, data class, nullable handling with if let, structured concurrency with scope — to the .NET runtime.
Nothing wrong with that at all, I love to see the increased interest in language design, but I wouldn't read a shift in preferences into this wave of PLs. It's a shift in who is writing PLs, not a shift in preferences.
I'm less familiar with Swift but from a design point of view Go and Kotlin have really different ergonomics. Kotlin leans in really hard to creating DSLs etc. whereas Go avoids all that stuff like the plague. To me this makes the tag line a little confusing, like what does this imply for the design of this language?
You've been tricked by the SCP, this is the dupe - check the IDs (it's older than the one you linked to.. although there's also the one 31 days ago /w 9 points/2 comments from the OP)
Things like Zig, D, Odin, Rust, etc, are outliers. Most new programming languages are used only by their creators.
It's hard for a new language to find its feet, and make a name for itself. Unless its created by a big company with a lot of clout and internal users. (e.g. Rust, Go).
People keep creating new languages because it's educational, interesting, and sometimes even fun. Doesn't mean they'll get used, and it doesn't mean they're pointless.
Of course you learn very little if you make an LLM write the damn thing. But that's a different story.
There is gleam that is popular, and not backed by a huge company. Then there is also lisette for Go, thats very similar but targets Go instead of the beam.
New languages have space, and its just stupid "to stick to the only one i ever tried", then you just end like a PHP dev who just refuses to learn anything other than PHP.
For sure, learning new languages is helpful even if you don't use them. But that said there's also a significant difference between playing with new/toy languages for fun, and using them in production.
Trying to hire Haskal programmers to keep your product alive will be significantly more effort than finding a C, Go, Java, Rust, or similar programmer instead.
I like languages, I explore lots of them, but at work I stick to "obvious" choices because colleagues use them, know them, and it fits into the shared infrastrcture. It's okay to introduce new things, but it requires buy-in, and persuasion. Not just one dev saying "That new CLI we wanted? I started in Racket/Odin/Wren/Lua/whatever."
In my experience the strengths of Go are mostly - Deployability via single-file static binaries - Simple syntax that anyone can learn (no exceptions, no classes or inheritance) - Wicked fast compile times
And the strengths of C# are - Powerful language with null-safety and lots of syntax sugar - Runtime-level coroutines so you don't need `async/await` everywhere
G# seems like it has the _worst_ of both worlds, not the best. It's fun to write compilers, and good on them for doing it, but no thank you for real use
If I'm not mistaken, that isn't the case. Could you elaborate?
AOT is not all that useful yet for many applications as important libraries still don't support it. So more something for things like CLI tools with a small scope.
It's not quite the same as with Go, the binaries get large if you can't trim them. But creating single-file self-contained executables is very much usable and works well otherwise.
splitting hairs, but its is not independent. AoT is a required pre-requisite for single-binary creation. You can't create single-binaries with JIT. And that is the big hurdle, lot of libraries do not support AoT and that is the blocker to create single-file binary. Once you have the AoT figured out, the single-binary creation is easy.
.NET AOT right now is a very specialized solution that isn't widely applicable. Self-contained and single-file binaries do work pretty much out of the box already.
See the documention here for the PublishSingleFile and SelfContained options:
https://learn.microsoft.com/en-us/dotnet/core/deploying/sing...
They have in fairness fixed a lot of the worst aspects of this by adding basically a second language to it but e.g. I massively prefer writing F# if purely because if I want to do something I can just to it rather than first implementing public static DoThing : IDoThing
In other words, C# is a bad language because you don't like it?
What does prevent you from "just do it" in C# without extra classes and interfaces?
> @DllImport("libc", EntryPoint: "strlen", CharSet: CharSet.Ansi)
I would argue that they made something I suspect many Go developers will dislike. I know I absolutely hate it. If I wanted to do things like that I might as well use C#. Then again, these days I'm shifting more and more of my development to either Python (which is objectively an awesome language that also sucks) or Rust. While one of my favorite features of any programming language is the Go modules with single folders and upper and lower cases for private/public. I am becoming a fan of how rust does structs with impl methods.
Anyway...
20 years ago there was some momentum behind Visual Basic .Net; but the language was so similar to C# that it just wasn't worth using. There was a joke that .Net was a "skinnable language."
BTW, there's a whole nitpicky/semantic argument that C# isn't null safe because of the null forgiving operator. That will probably come into play with G# if the null forgiving operator can be used from C# to pass null into G# code that doesn't expect it.
IronPython[0] and IronRuby[1] would like a word... Largely so they could be remembered.
0 - https://en.wikipedia.org/wiki/IronPython
1 - https://en.wikipedia.org/wiki/IronRuby
I remember the MS documentation had sample code in all the variants of .NET languages they created (C#, F#, VB.NET), and of course there were decompilers that let you choose which one to target, with many other translation tools available between them.
Not that either of these things is disqualifying but AI really has make it difficult to know how established a project actually is.
https://github.com/DavidObando/gsharp/tree/9579dd6626801f089...
Calling a language with `let` instead of `const` and async/await and iterators and classes "Go" is plain just incorrect. This G# is more similar to TypeScript than Go.
The ONE feature that C# really needs is payload enums with `match` instead of C#'s current pattern matching with `switch` anyways, and Rust is more similar to Go anyways so why not copy from Rust instead? I'm honestly baffled.
So very concise. And this is not even including the error wrapping that is recommended.
Like, if you go by function: ReadData(has err)-> ParseData(has err) -> ProcessData(no err)
Instead of having functions that can fail dynamically all over your codebase.
> Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language.
they're coming
The null patterns predate these unions and the relevant section of the documentation is showing that you can use nullable unions, not that you have to or should use them. Other examples also show a fully closed Result<T, E> type that yeah would be great for projects hoping to eliminate more nullable code.
- what is the thought process that goes into making a programming language
- what is this field of study or discipline called?
- why do we have so many programming languages? what purpose do they intend to solve and how do we know what purpose a programming language was made for?
- for example, why was swift made if objective c exists and why was objective c made if c++ exists?
Write a parser from your language’s syntax to an AST (Abstract Syntax Tree) which is the representation of the code in memory. Now write a function from the AST to the compiler output format. That can be some executable binary format (see https://en.wikipedia.org/wiki/Comparison_of_executable_file_...) or some other language, like C (a common target) or something made exactly for that like LLVM (used by clang and Rust), Java or C# bytecode if you don’t mind requiring a VM to run the application. I’ve written Java bytecode generators and it’s surprisingly easy! Getting a simple language off the ground is a lot of fun and not a huge challenge.
We have so many programming languages because it's a fun and relatively easy thing to start, and lots of people have differing opinions of how it should be done. Also making a programming language seems like a difficult thing from the outside so it has a certain allure.
Swift exists because objective c has archaic language design that modern developers reject. Objective C exists because as far as I know at the time smalltalk style object oriented programming was hip and C++ made the wrong decisions in their eyes. It could also be that C++ wasn't popular enough yet at that point for Apple to commit to it. In that period basically all major operating systems went different ways. The Unix derivatives went all in on plain C, Microsoft went C++ and Apple objective c, though I think OSX itself is plain C for the most part.
We have so many programming languages because they tend to have a particular niche in which they're useful. Many languages are still in use even though they're very old (C, FORTRAN, COBOL), and others just keep getting updated over time and have a large userbase (Java, Perl, Ruby, Python).
99.99% of all new programming languages never get a critical mass of users. People create a new language to learn something, and they're the only user. e.g. I've written a few FORTHs, have spent the past few weeks on writing a lisp compiler, and in the past wrote BASIC interpeters for fun.
If you want to make your own "crafting interpreters" is a good read:
https://craftinginterpreters.com/contents.html
But there are a million other tutorials on writing a simple lexer/parser/interpreter/compiler, and a lot of academic literature (e.g. The Dragon Book).
- "I want a language that works a little differently"
- programming language theory (PLT), generally
- languages are tools. the authors should explain what their languages are best suited for
- Obj C and C++ were both developed around the same time as extensions of C. Obj C was focused on message passing and Smalltalk's object system, while C++ was focused on adding as many abstractions as possible to C. Neither language has good support for avoiding null pointer dereferences, one of the primary things Swift addresses with its richer type system and Optionals.
https://craftinginterpreters.com/
the hardest part was what came next: the code generation. despite producing c# instead of MSIL. The features I use are: static and dynamic traits, pattern matching, and a concurrentML.
It is actually quite simple when you don't have to do closure conversion yourself.
The big drawback that I never managed to sort out is how to integrate with visual debuggers. How to generate GDB source mappings (or .PDB source mappings) that reference the original LanguageX source files.
So you end up with a toy language that is un-debuggable. Which is not nearly as much fun as it should be.
``` G# brings Go-, Kotlin-, and Swift-style ergonomics — packages, func, data class, nullable handling with if let, structured concurrency with scope — to the .NET runtime. Source compiles directly to managed assemblies. ```
This is a decent description - but as someone also building a language in a similar space - who isn't super familiar with the .NET runtime... My first question is... Why not C#?
I'm by no means a C# expert, but I thought most of this was supposed to be in C#. C# is not terribly un-ergonomic, and Go is simple, but not really ergonomic except for Goroutines...
`packages` and `func` being the first two selling points is alarming. Sure, people probably prefer `fn foo() -> Dog` over `Dog foo()`. No one's picking a language for that. C# has namespaces... C# has `record` and `record struct`. C# has not-ideal nil handling, but it still has it. I'm not convinced `if let` is better enough to be a selling point - a lot of people don't like that!
Your main selling point seems like `scope` and your concurrency model vs C#, but C#'s is not exactly terrible...
Rich Hickey has a joke about semi-colons in language design, and your main pitch seems to sell yourself short.
Btw, I think your GitHub page does your language a lot better justice.
I didn't see semicolons, but I saw plenty of {} braces, and I can't explain why they're needed.
https://github.com/Syzygies/Compare
"I'm already quite sure how I will die: I'll read another article on Hacker News about a new programming language where I see nothing new, and I'll read that they included {}; to make C programmers comfortable. I'll have a massive stroke."
"Curly braces" (a.k.a. "{}") make lexicographical scope simpler to manage for lexers and parsers. Alternate grammars increase compiler complexity, excluding trivial token replacement.
As for semicolons, they are only a linguistic requirement for supporting multiple executable statements on the same source-code line.
C# grew all those features over time. It had to leave syntax to support old patterns to preserve backwards compatibility. Thus, the syntax has grown a bit noisy over time to support all those features. This is reboot keeping the newer ergonomics and streamlining the syntax.
I probably wouldn’t adopt it for existing projects or use .Net for any future project, but it looks really nice for what it is.
Maybe .NET AOT will get there one day..
It was nice. Feel free to take a look
https://github.com/OctopusDeploy/OtelImporter
Read the docs of what’s missing, if you are honestly interested in what’s missing.
https://learn.microsoft.com/en-us/dotnet/core/deploying/nati...
Reflection, is one thing. Of course some runtime stuff are missing, but the problem is that no one is using source generators before trying out aot, so as soon you try aot you just meet a wall of compilation errors. Most people just want to be able parse a json file without jumping through hoops. Bad DX
Everyone should be exploring source generators already whether or not they expect to try out AOT.
[1] Debugging source generated RegExes is a dream, including being able to breakpoint inside a RegEx in the .g.cs file should you need to trying to get a tricky RegEx right. The code generated by the RegEx Source Generator is incredibly readable and includes great comments that explain what the RegEx does, step by step. Those comments show up as documentation comments on the partial .cs file side once the file is generated and can be used to double check that the RegEx you wrote matches what you expect it to do as you write/update the RegEx and the source gets regenerated (which happens pretty fast).
[1] https://learn.microsoft.com/en-us/dotnet/api/system.runtime....
This works perfectly fine with AoT:
As you can see, there are no UnsafeAccessorAttribute's. Plain old reflection that just works (why should it not?)https://godbolt.org/z/Yv8hadYqv
I definitely don't fully understand the landscape, so I could certainly be wrong, but I assumed that normal reflection didn't work in AOT because after trimming that method may or may not be there. If it was never called in a normal way then the compiler doesn't know that `Console.WriteLine` was being used as `GetMethod` may have a runtime value as a string rather than a constant value known at compile time. If the compiler didn't know it was being called then it will be trimmed out of the final binary whereas with `UnsafeAccessorAttribute` it provides the information required to not trim it.
Edit: I tried the following https://sharplab.io/#v2:D4AQTAjAsAUCAMACEEB0AlApgMwDaYGMAXAS... and it fails when I provide the type and method for Console.WriteLine as arguments. If I was to add `typeof(Console).GetMethod(args[1], [typeof(string)])!.Invoke(null, ["dummy"]);` to it before the `Type.GetType` call it seems to be enough to not trim out the `Console` type and the `WriteLine` method. The compiler seems to at least be smart that way.
why do people still accept CSP? It is simple to do some things in it, bit please just give me concurrentML with "simple" channels for that kind of work , and proper channels for any kind of hard stuff. I have had to write things in go that took me days to get straight that would have been 20 trivial lines in any concurrentML implementation.
Maybe similar to OpenJDK and Oracle?
I feel like we've done full circle. Languages are back to being (mostly) procedural. I'm not sure I like it, but it seems that this is what people prefer.
Personally, I'd rather see something like dependant types on a dotnet language. An addition, not just a simplification.
Is this an actual shift, or is this just what happens when LLMs make it possible for anyone to build a language quickly?
This one feels less like someone thought carefully about what semantics they wanted to have and more like someone without a lot of familiarity with the design space of programming languages decided to build one that had all their favorite features from the languages that they already know:
> G# brings Go-, Kotlin-, and Swift-style ergonomics — packages, func, data class, nullable handling with if let, structured concurrency with scope — to the .NET runtime.
Nothing wrong with that at all, I love to see the increased interest in language design, but I wouldn't read a shift in preferences into this wave of PLs. It's a shift in who is writing PLs, not a shift in preferences.
What a great era.
Means "for 1 to 4". Kill me now.
if a ranges are inclusive, you get used to it. if it is arbitrary it is awful.
Have to ask what is the point of .NET is it even needed being the navel gazing MS fraternity?
According to Tiobe index and stack overflow developer survey, it's also a lot more used than Go, so there's that.
My anti MS is a reflex from many years of torment!
It's hard for a new language to find its feet, and make a name for itself. Unless its created by a big company with a lot of clout and internal users. (e.g. Rust, Go).
People keep creating new languages because it's educational, interesting, and sometimes even fun. Doesn't mean they'll get used, and it doesn't mean they're pointless.
Of course you learn very little if you make an LLM write the damn thing. But that's a different story.
New languages have space, and its just stupid "to stick to the only one i ever tried", then you just end like a PHP dev who just refuses to learn anything other than PHP.
Trying to hire Haskal programmers to keep your product alive will be significantly more effort than finding a C, Go, Java, Rust, or similar programmer instead.
I like languages, I explore lots of them, but at work I stick to "obvious" choices because colleagues use them, know them, and it fits into the shared infrastrcture. It's okay to introduce new things, but it requires buy-in, and persuasion. Not just one dev saying "That new CLI we wanted? I started in Racket/Odin/Wren/Lua/whatever."