Author here. I'm the engineering co-founder of PopCap Games. I left PopCap after the EA acquisition, and I've been working on this project mostly full-time for the last five years.
Before Beef, I was developing game code in C# and engine code in C++ and I felt C# was just much more pleasant to work with - faster compile times, better IDE tooling, better errors, etc. Then it struck me that none of the things I liked about C# really had anything to do with the JIT or the GC, and it may be possible to create a "best of" merging between C# and C++.
I know there are other "C replacement" contenders out there - the differences are probably best explained through Beef's specific design goals listed at https://www.beeflang.org/docs/foreward/
When making the Inko website I saw a bunch of other language websites (e.g. D's website) use this approach, so I copied the idea. I'm glad it turned out useful :)
I'd like to just add a +1 to this. I had a tough time finding some good code examples and would love to see a small example of code in the readme. Something beyond a hello world, preferably but that's just me
Hey – cool stuff and thank you for taking the time to respond to comments here!
Some questions and feedback:
1. Did you start this project at PopCap and if so, are any of their games developed using a version of Beef? Do you know of any other games developed with Beef? I looked around the site but couldn't find any such information.
2. How would you use Beef with popular game engines like Unity or Unreal? Or is this language mainly intended for engine development as opposed to game logic?
3. Given the focus on developer "ergonomics" if you will, while retaining high performance execution characteristics – are there any representative benchmarking examples where you can showcase both great performance and "nicer" code?
Regarding that last question, a representative example in my mind might be something like a small raytracing engine. Something sufficiently complex that performance matters, but stils simple enough that someone familiar with the domain (and, presumably, a counterexample language like C++) could grok the Beef code and see the benefits in a show-me-don't-tell-me kind of manner. What do you think?
1) I started this project a few years after leaving PopCap. This is the very first public release - only a couple people have seen it before now so there hasn't been a chance for anyone else to build anything with it yet.
2) This is intended for both engine development and game logic. Using alternate languages with Unreal or Unity is nearly impossible at the moment- likely Rust will make inroads there before BeefLang.
I'm impressed by your C# reimplementation [0]! (Yes, I can tell it is different). Not sure what the aspiration is, but I'd be surprised if you don't have an offer from Microsoft in the next few years (assuming they haven't already tried to buy you out). Unfortunately I can't find any mention of threads/parallelism on your website, which I'm sure are present in the language.
Ps. If you're still looking for worthy features, might I suggest f#'s units of measure [1]? They are enforced by the compiler and stripped at runtime, so they are fairly simple to implement.
Looks nice, unlike pretty much every other language i see posted here and in proggit it has a full tool suite (with IDE, debugger and even profiler) and documentation. It does look like a professional quality product.
EDIT: i think you need to add some information about which systems exactly are supported, especially for Windows where not everyone is running the latest version.
Also what about backwards compatibility? It might be too soon considering a 0.x release but how often does the language break existing code and what are the plans for after 1.0? No break at all no matter the cost, breaks every major version, total breakage regardless of version, ?
Great question - I've thought a lot about backward compatibility but I don't have a good answer yet. The whole Python 2 vs 3 nightmare has given me a couple sleepless nights though.
May I recommend d's scheme? I personally find it works quite well. Essentially, breaking features are introduced as a 'preview' that you have to opt into with a compiler flag. After a period of some time, it is changed so that the old and new behaviours can co-exist, but a deprecation warning is issued where the old behaviour is found. After some more time, the warning is changed to an error, but with an option flag to change it back to a deprecation. Then, finally, it is removed completely for the compiler.
This makes the maintainers' job a bit harder, but not by a lot, and as a user I find it a nice medium of stability and progress.
I don’t maintain much software with downstream users, but I would expect feature flags like this to make the job also easier for maintainers. It’s a little bit more code, but since you don’t break anything for your users you can take your time and don’t need to rush to push out fixes for new features, since these are opt-in first.
2: "Small" userbase: changes produce grumbling, community adjusts over time, old code is successfully forgotten (deleted + no nostalgia)
3: Very Large™ userbase: even TNT won't change the language
Each of these is relative: (3) has happened with Python (famously explosively), Rust, Go... and also Lua, awk, FORTH. Language size ("volume") seems to have no impact; once a language becomes known for a certain way of doing things beyond a certain scale, trying to go against that (even as the language creator) will land you in a strange, undefined uncanney valley that's not precisely un-idiomatic, but... everyone will still try and steer/corral/etc you back to the "established way".
Obviously (2) represents the perfect ideal here. (Well it wins by default, since (1) is socially depressing :) )
So, one approach could be to try lots of ideas (at a pace that keeps up the creative energy to enjoy the effort) early on.
The key in this case seems to be figuring out the magic threshold point where the community is
- large enough to provide constructive feedback and help the project substantively grow
- small enough to stomach fundamental, relearn-everything-you-learned, changes
- cohesive enough not to be disbanded by the impact of said changes
and carefully ratelimiting publicity and knowledge spread to control ecosystem growth, in a way that does not rein it in.
The dynamics of what defines this balance seem to be specific to each project.
Hey! Just wanted to say thanks for the great PopCap games over the years. I sunk a lot of hours into Insaniquarium, Peggle, etc.
I'm really enjoying this renaissance of "C replacement" languages like Beef, Jai, Zig, Rust, etc. It would be cool to have a table comparing them all, hyperpolyglot-style.
A hint from a "professional": It would help a lot if you'd give a single-paragraph positioning in the field of PLs. In your case at first glance it looks like "first-order (?), monomorphic(?) nominally typed, strictly evaluated, object-oriented (?), ahead-of-time compiled, with a context-free syntax and no (?) macros." As you can see, there are a lot of question marks you could answer ;).
great to see you here! quick question- you wouldn't happen to be BF? One of the first games I played on PC was ARC. Those leagues got me into scripting, which led me to Purdue CS, which led me to my career today.
just wanted to give a shout out to you & JV. you guys had a lot of influence over a generation of ARCers, some of which still play games together. so, thanks, and cool to see this from you. I will check it out and show my engineers
Wow. That's amazing- yes, I am BF from ARC. I haven't heard from an ARC player in some time -- maybe ARC inspiring you to get that Purdue CS degree counteracts me and JV dropping out of Purdue.
JV just texted me the other day to pitch ARC VR actually. He went the VR route, founding Pluto VR after PopCap.
Search for "attack retrieve capture". It's a multiplayer game from 1997 that I made with a friend in college. That friend and I co-founded of PopCap Games with another game designer we met during the development of ARC (actually, our "producer" on the game when we licensed it to TEN.net).
I seem to remember one of the PopCap founders being active on comp.sys.ibm.pc.games, back when Brad Wardell and some of the other later-high-profile designers were in the conversation as well, mid 90s or so IIRC.
Would that have been one of you too? Those were gaming glory days for me, with limited forums for discussion and everyone gravitating to what there was. You got to rub shoulders with some pretty cool people, digitally speaking.
Also, how weird is it that the public net has been around long enough to ask things like if we met on the internet 25 years ago? My mind still reels.
Beyond the excuse to be a useful "dogfood project" of the language, was there any other intentional reason to focus on a custom IDE rather than the Language Server Protocol and multi-IDE support?
A LSP didn't give me enough control over the IDE environment to create the development experience I wanted. I was also very interested in building a very good hot code swapping environment and that's not possible with a generic IDE/LSP.
An LSP implementation can be fairly useful although if you want to let backend services like sourcegraph code search support your language better. Not to mention other future tooling or doing development with a beefy datacenter machine to have fast compiles or work with large codebases.
I would suggest adding LSP support as a future todo.
I think you should put this in the project readme. I just kind of glossed over the description while reading it before I checked the HN comments, but knowing who you are makes the project more interesting and significant to me.
Sorry this isn't about the language, but I just wanted to tell you that I was born in '97 and during my childhood my mother used to play Bookworm with me every day to teach me reading and spelling.
She also may or may not have had a serious addiction to Bejeweled.
I had forgotten about that for so long, thanks for the childhood memories.
Very cool; I’m looking forward to playing with it. Just wondering - what’s the current state? Is the core language pretty well baked at this point, or is it open to changes?
Good question. For one, there's also a custom optimized-debug backend that's used by default for Debug builds which is a lot faster than LLVM. Secondly, there's incremental compilation with an object cache so minor changes only general minor rebuilds.
For a clean release build, however, LLVM will dominate the compile time as expected. Compared to C/C++, however, there is less duplication of ODR'd code (ie- methods defined in headers such as template methods) and less debug information duplication so backend time is lower.
Since you are working on debug-specific backend, have you considered Cranelift [1]? In case you never heard of it, it was especially intended for fast codegen (because it's being used to compile WASM in Firefox), and Rust wants to be able to use it for their own debug build. If you were aware of it and decided not to use it, I'd love to know what are your rationals.
Hah. Yes, actually I did. I wrote a C#-to-C++ transpiler and a VM wrapper with a concurrent GC. This predated Unity's IL2CPP by about 6 months.
Compile times were a big issue, and the little edges of the language and libraries were problematic since they were built around a JIT. Then it struck me that I don't really care about the JIT, and the reason I liked C# had nothing to do with the GC, and it would be much better to just make a slight variation of C# that was statically compiled and without a GC.
I just followed along all the obvious next steps from there, and here we are 5 years later.
How do you feel about .NET Core's growing support for AOT, and better manual/stack allocation support with Span<T> in ? If you had to start from scratch would you give native C# another try? What do you think is still missing from the language?
What GUI toolkit is used for the IDE? Is the IDE multi-platform? I tried the Windows application and it had complaints about Visual Studio not being found when building the sample app. What's the dependence on Visual Studio about? Also the IDE died in a unrecoverable way when trying to do a single-step on the first sample application.
The GUI is custom. The IDE is Windows-only at the moment, but there's also a command-line compiler for other platforms. VS is required for linking (even when using the LLVM linker).
I'd be interested in more information about the IDE crash.
Advice from a fellow dev: add a crash handler and set it up for an automatic submission of crash reports (symbolicated callstacks of all threads) via HTTP POST to a server.
Better yet, turn it into something that others can use easily by configuring things like the server to which send the reports.
How much work is it to port the IDE to other platforms?
The IDE is maybe one of the nice/important aspects of this project, but then this really should not be Windows-only. Or maybe that are your priorities, but then I would not expect that it gets much adoption outside of the Windows world, but maybe this is ok for you.
I picked the same and use the menu to build, but I don't have VisualStudio, so perhaps the sample didn't really build. Then I was clicking around the menu and chose the Single-Step option on the menu (F11? F10?) when the IDE crashed.
Well, they are not functions and they are not macros. It seemed appropriate to overload the 'mixin' name, but it's not too late to find a better name.
Even if Beef supported class mixins, I would say "there's class mixins and method mixins". D does something similar with template mixins vs a mixin statement that compiles strings as code.
Do you think Mormons object to coding in Java? Do vegetarians only use bash and zsh because fish is offensive? Do Muslims refuse to deploy snort because their mascot is a pig? Do Christians avoid FreeBSD because of its devil or Unixes as a whole because of daemons?
The only people who will be offended are those who seek to be (and even better: if they're offended on behalf of others which is one of the most patronising behaviours imaginable)
Names are important. For what it's worth, the name 'beef' is peculiar to me. At first I thought it was a joke language like Brainfuck or ArnoldC. Java, fish, snort and cartoon devils are not nearly as culturally charged on many levels as dead cow flesh and all it invokes both good and bad. Where do you draw the line? A programming language called 'Christ'? 'Penis'? 'Dogmeat'? I'm sure you can think of some less obviously taboo. The only people who will be offended are those who seek to be, but that doesn't mean the name doesn't matter.
I think also out of the box standard library features. You can make production ready web apps. Also their initial approach to getting / sharing packages imho is useful.
So a decent package manager would do wonders. Rust has Cargo which does builds and packages. D has dub as well.
Definitely recommend making code sharing / reuse a breeze.
Thank you for working on this awesome project. One additional commentary I always make is that I wish Go and Rust had even a basic editor like the one Racket has: you can edit, and compile. You beat me to that suggestion so I'll keep an eye on your project.
Is there any possibility that you'll include some efforts towards doing back-end networking with this language as well? I could see multiplayer games needing servers after all.
All these 4 points are valid and did help golang but I think what took golang to the moon was:
- the immense success of docker based on it which made everyone build their devops tools in go (kubernetes helped too later)
- a very solid and stable http library included in stdlib (plus other networking goodies to easily run your own ssh endpoint in a few lines of code)
tl;dr to get your language some traction, make it solve at least one problem much better than the competition and have someone build a super popular open source project on it.
Congrats on the release. This looks like the first C and/or C++ replacement I might actually give a significant whirl. I enjoy programming in C as a hobby-grade thing, but it gets challenging organizationally fairly quickly for the sort of full applications I usually build. And I'm also a big fan of the C# "mouthfeel," so to speak. I have tried Rust, and while I'm a fan of its design goals, etc., fully wrapping my mind around the ownership/lifetime system is just not something I have the mental capacity for right now. I don't use these systems langs enough professionally (read: at all) to justify the labor cost.
This also seems pretty damn polished for it being the first time anyone publicly has gotten a look at it. I mean, a full IDE on day one is nuts.
I know Beef seems sharply tuned for game dev (another hobby of mine), but do you see Beef as being usable for general purpose systems/application development? Is there anything about it that would discourage its use for a standard desktop GUI app? And because I'm curious and haven't seen this answered elsewhere, is the Beef IDE also written in Beef, for some tasty beefy dogfood?
edit: Nevermind on that last question, I found it answered in the guide (in the affirmative). Nice!
> Is there anything about it that would discourage its use for a standard desktop GUI app?
Complete lack of accessibility support, particularly for blind users via screen readers, in the included GUI toolkit. Please don't use this for any application that people will be required to use in their job or education.
Also, to be clear- the custom GUI library that the IDE uses is NOT a general-purpose GUI library; it is a support library for the IDE and other BeefLang tools. A true general-purpose GUI would be quite a lot more flexible and also much more complicated... which is not something that is intended for this particular GUI library.
I did eventually find that notice in the documentation, after I posted my comment (and sent you an email). I should have read more of the docs first.
Still, I wonder why you chose to write your own GUI just for the Beef IDE (and installer) rather than use an existing general-purpose GUI. Were you aware of the accessibility issue?
Hi Andrew- of course I've been following Zig. Thanks for your trailblazing efforts in the "C replacement" space.
It's true that symbols in 'false' preprocessor blocks will not be caught. Maybe it's best said "if the compiler will find the symbol when you compile, then the symbol renamer will find it when you rename". Which is definitely not true for most symbol renames I dare to attempt in C++ IDEs.
Ah- for BeefLang that's less of a problem since even unreachable code is typechecked (without code generation). But yeah your problem sounds very hard. I guess I don't fully understand why you would only want reachable functions to be listed in documentation...
It looks like the author of this language is using it for game development. What features does Beef provide that other languages don't from a performance perspective? It looks like it has a class & object style. Does it give you tools to control memory layout of those allocations for performance? I know some game devs have commented that the reason C++ classes aren't used in their entity system is memory locality & latency issues.
There's a split between class and struct. Classes are reference types and have more 'features', and structs are a lot like C structs - you have complete control over their layout and allocation.
There's future plans to add more high-perf sugars like automating some SoA and AoSoA layouts, but you can do all that manually right now.
You should probably do some perf analysis to show how Beef performs vs C / C++ for game related tasks.
Also it would be awesome for you to make a few code samples / tutorials on how to get started with game development with Beef. I'm sure it would attract a lot of people to your language if you show some "proof" it is a nice language for gamedev!
I love the concept of this language! Even though a lot of attempts have been made, I think no one has really filled the "more ergonomic C" slot yet, and I would be happy if this manages.
I am sorry to see semicolons though. I have never missed semicolons after moving to languages where they're not required, and it's always a bummer going in the opposite direction.
Looking lightly at some of the code and the screenshot provided, I'd like to compliment on the look of the language. A lot of the newer languages coming out mess with the "normal syntax" way too much, which discourages me from learning it. Beef actually looks like I could sit down, and learn the features of the language, rather than relearning a new syntax that wouldn't translate well.
There are some optional memory safeties, including real-time leak detection, but this language targets an audience who value performance over total memory safety.
For someone looking for a C replacement where memory safety is absolutely critical (ie- open server applications) then Rust may be a better fit.
Linear types (and affine types, as in Rust) only buy you some memory safety (preventing use-after-frees, and memory leaks although that's not really a safety issue).
The more important part of memory safety is preventing out-of-bounds accesses. Rust, Ada, and (it seems) Beef sacrifice performance for memory safety here by having runtime bounds checking. (Though there is not much performance cost to this and all of those have options to turn off runtime bounds checking anyway.)
The only performance-oriented language I'm aware of that is fully memory-safe at compile time is ATS‚ via a combination of linear types and dependent types, and using ATS is… cumbersome.
It's better to manually hoist the bound checks so that they happen before any critical loop. The compiler often can't do this because it has to preserve the partial effects of where the failed bounds check happens, but that's generally not what you really want; if anything, you'd rather fail fast.
leaks aren't unsafe though. Things like bounds checking and aliasing guarantees are like 90% of the memory safety issues you care about, and those can be performant.
> Leaks can be detected in realtime with the debug memory manager. Reachable memory will be continuously traced at runtime and memory which is no longer reachable but has not been properly freed will be immediately reported as a leak...
Sounds like it doesn't have a Garbage Collector, but a "Garbage Detector" that's only active for debug builds?
Yes, this is right - there is what is essentially a fully-functional "garbage collector" but its only job is to detect leaks in debug builds. Well, it also is used for detecting illegal memory layout changes during hot code changes...
One may say "then why not just make the GC optional like D", but when you design a library you really need to either design it for a GC or for manual memory management. Even for the basic string type - if Beef was a GC'd language then String would be immutable, but it's not so String is mutable. Totally different designs.
Hello - the IDE focus looks very attractive from an indie-engine developer's perspective(small scale development always gains the most from having unified, consistent tooling). Will this be a customizable environment to e.g. assist working with asset dependencies?
At a glance I don't have any other major remarks. It looks very much like it's on the same general trajectory as Zig, which is probably a good sign that that design space is in the right ballpark for low-level real-time systems. There is some attraction in having automatic memory available for application-level tasks with more indefinite boundaries(editing tools tend to develop compiler-like qualities which in turn creates a need for more introspective style), though it's probably outside the scope of this language and might be suitable for a scripting-layer approach instead.
What's the concurrency model and what thread/coroutine support is available or planned? I see some supporting classes in the System.Threading namespace.
The most obvious choice would be async/await support - no specific plans yet, though.
The concurrency model is, like C++ or even C#: sequential consistency for data-race-free programs (SC-DRF). No green threads or anything crazy, no 'message passing', just normal system threads, normal locks, you control how you access memory yourself. You do synchronization just like you'd do in C/C++.
If you go the route of async/await support - I went through the arduous process of figuring this out for zig (for which I think our design goals are nearly identical), and went through a couple different iterations. I have experience with using LLVM's coroutines API and abandoning it to codegen them manually. Would be happy to have a brainstorming chat with you sometime if you're interested.
I would appreciate it if more languages had something like ucontext_t or byuu/co, because I don't enjoy tagging every call site with "await" whenever I change a method to do something that might consume some time (and every call site of those functions containing call sites too, and so on), and because I do enjoy being able to write code that uses speculative execution (like for time-travel netcode for a 2d fighting game) without manually converting all my imperative code to a state machine like a compiler should do.
I am a bit of a snob, maybe, but I've come to think one of the bare minimum features for any language is copyable coroutines.
Sorry but I cannot stand the separation of structs/classes and 'classes' being 'by reference' and structs by value types. It's the reason I don't like D.
C++ makes a lot more sense: the type declaration is not coupled to specific allocation patterns by default, which to me is a lot better choice than structs and classes ala D.
Rhis distinction also appears in C# in exactly the same way and I don't find it that hard to use. Also, Beef allows you to explicitly allocate objects on the stack via "scope:". So being by vale or by reference is a default rather than set in stone.
C++ is my bread and butter, but even I consider "struct and class are exactly the same except for default access specifiers" to be pointlessly redundant. I mean, the language could get rid of one of them, but I think the options offered here make sense.
I haven't reviewed your language, but from a fellow software engineer, congrats on your work! It takes a lot of grit to make a programming language. I hope to make one as well one day. If you blog about your experiences about the non-technical challenges, I would definitely read it.
Do you think you will add nullability / optionals into the the type system along with ADT types? (Think swift enum's with associated types). I think structurally they are fairly simple, but very powerful.
There are nullables (like C# nullables), same syntax: "int? a = null;". There's also algebraic data types like Swift's enum. Quite a lot like Swift's enum, actually. See bottom example in enum section: https://www.beeflang.org/docs/language-guide/datatypes/#enum...
It's as fast as C, since anything you can express in C can be expressed in BeefLang.
The real question is how fast an idiomatic expression of an identical complex program is in both language. Well, that might not even be the question- it may be more like "if presented with a problem that requires writing a program, what are the characteristics of the solution to that problem if the language chosen is X vs Y". Maybe?
Anyway, I don't think anyone has figured out how to properly compare programming languages yet in that way other than "try it and see if it works better for you than other things you've tried before".
Is there planned console support? I assume that's the hardest group of platforms for any engine to target, and is part of why Unity and Unreal have such a stranglehold on the market.
Console support important. That being said, there's a question of what console support means. For a programming language, that generally just means the compiler needs to be capable of generating binaries for the given target processor. The issue of how to interact with the hardware itself and how to participate in the toolchain provided by the console vendor is much more difficult and is outside the scope of the language/compiler.
The ideal case is for an engine such to embrace Beef and work through those issues.
Chucklefish was an early(ish) adopter of Rust and tried to maintain an XBox/PS4/Switch toolchain but eventually abandoned it. Rust is probably a good example of a popular "alternative language" that may pave the way for BeefLang and others to work their way into those spaces.
Fellow dev here, I think you're wrong on this part:
> The issue of how to interact with the hardware itself and how to participate in the toolchain provided by the console vendor is much more difficult and is outside the scope of the language/compiler.
I've been looking for a language that would allow gradual transition from C++ for example. If you have a C++ SDK, you could still write your whole engine or just some modules in Beef.
I was speaking more about when you have to conform to Nintendo's Switch build system (whatever that looks like - NDA) and you can't control much of that.
If you do have more control then you're in a much better situation, but crossing language boundaries can still be tricky.
Generally you end up having to write "wrapper" code to make those language boundaries palatable. There are code generators like SWIG to handle those things, and some languages like Zig handle importing of c headers, but if the C++ library your trying to use is returning a std::shared_ptr then that's not going to be a very pleasant construct for you to attempt to work with in any language besides C++.
If you can split your code sections into simple and clean C-like interfaces then the job becomes much, much easier.
Awesome, I love seeing new languages (and I hope to share mine in good time). I didn't see it, but a good tutorial introducing new ideas would be good.
This looks like it has all the missing performance oriented features I wish I had while I was developing the engine of my game[0] using C#. I will definitely try it out for my next game/prototype!
I like the idea of beef, c# like syntax but compiled. One question which I couldn’t find a answer to on the website, can beef be used to create shared libraries such as dlls? I’m thinking this could be a serious replacement for C/C++. I’ve tried go, it’s interoperability with the outside is not very good, and rust requires too much of a learning curve.
The way append allocations work makes me think that you can't have classes on the stack? That seems at odds with the design goals of making the language suitable for high performance applications - I mean sure you can use structs for everything but at that point you're kinda giving up the benefit of using a modern language.
For us to pick up a new language and potentially use it for work, I need the confidence that this language is going to stick around and have a user base.
Go and Rust benefitted from being backed by Google / Mozilla.
Whereas, Beef doesn’t even have a corresponding game engine. Have you thought about you will grow the language usebase?
What are your thoughts on Unity's Burst compiler? It allows for writing C# code that is compiled to code that is (theoretically) as performant (or even more so!) than regular C/C++ code.
1) VSCode was not able to accomplish the development experience I wanted, but I would certainly support a BeefLang language server for VSCode (and other editors/IDEs).
2) Like C, BeefLang idiomatically allows certain types of safe data patterns that the Rust checker would disallow since they cannot be reasonably statically proven to be safe. If you want to conform to Rust patterns then use Rust. If you don't, then BeefLang is another choice for you.
3) Do you mean if the IDE supports C++? It used to support Clang autocompletion and such, but it just wasn't anywhere near the quality of VS Intellisense so I just took it out and I still use VS for C++ editing.
Thanks. By c++ integration support I meant able to use C++ headers and link to C++ binaries.
This is really a great project, very pragmatically oriented, I wish you well. It's hard for any new language to gain momentum without underlying platform buy-in (i.e. Kotlin became 'a thing' when Google adopted it for Android). But I hope you can find an angle.
Does it have interactive features? Like messing with game state in a REPL while the game's running? The IDE looks really nice... made me wonder if it had something interactive as well.
Not OP, but I can definitely +1 this idea. It's a sorely missed component that must be thought through and implemented/specialized for literally every project (done in C/C++/etc anyway).
Hm- maybe your experiences are different, but for projects I've worked on, the game state is way too complicated to be usefully inspected and manipulated with a REPL. Especially if you are doing any sort of data-oriented design such as SoA or ECS.
There are quite a lot of other complicated factors such as "what thread does this run on?" and "when?". When you are debugging and hit a breakpoint then you basically have a REPL in the Immediate window...
At the language level, it feels that Beef has more concepts and is more complicated than Jai. I don't know which one is more expressive and more readable when actually used.
Seems great - I'll copy as many good ideas as I can. The root goals are very similar, but some issues in preference have resulted in very different approaches to meeting those goals.
This is correct - P/Invoke is not required because all interop datatypes can be expressed in BeefLang, whereas C# does not allow certain types of datatypes in structs (IE: pointers to structs, statically sized arrays).
I'm blown away by the completeness of this. The IDE is extremely full featured, albeit a little weird in places (eg scrolling with my laptop touchpad basically doesn't work). Love the Windows installer. But wow, go to definition, refactorings, debugger with great UX, callstack, etc.
Also love the example game. It's written so cleanly that I learned a thing or two about 2d gamedev just from scrolling through the code.
I love the little pragmatisms in the language, eg:
for (let entity in gGameApp.mEntities)
{
if (let enemy = entity as Enemy)
{
// .. do something with each enemy
}
}
That if/let/as combo there is something I'd have loved to have in many languages.
Also hats off for switch/case without break. Finally! I also love how you're mixing C/C++ "global enum value names" convenience with namespaced safety:
public static Result<(char32, int32)> TryDecode(char8* buf, int bufSize)
{
...
return .Err;
// not Result.Err, because the return type is given in the signature
}
I know that these little syntactical things are not the key challenges of language design, but obviously they're the first things I see, and I like the amount of attention you've given them. You really only have the opportunity to get them right at the very beginning.
I think the docs are a little sparse still (but that can be expected, of course). Eg:
I love that you made it easy to destruct fields like that, right there in the initializer expression, btw. Will probably kill the need for 90% of destructor methods out there.
- Apparently this converts floats to ints:
(.)(mX - entity.mX)
Or at least it does in HeroBullet.bf:15. I'm thinking maybe this does something similar as `.Err`, in that the dot makes it cast to whatever the expected type is in the function being called? I'm not sure though, it looks like a super powerful feature, maybe :-)
Finally, I believe .bf is also used for that other super convenient and performant language, Brainfuck. I doubt that causes any practical problems, but then again, why not just .beef?
Thanks for the checking out the language thoroughly, that's appreciated.
With "delete _", you are correct, the "_" refers to "the value in question", which is mRand in that case. When you have a switch statement, the "_" refers to the value being switched over.
The "." type is a special type meaning "the expected type here". So that's explicitly casting to the expected type, since an implicit cast from float to int is not allowed.
And yes, my apologies to Urban Müller for overloading his file extension, but it seemed the chances of that actually being a problem for someone were acceptably low and I really really preferred ".bf".
Come to think of it, this is an excellent opportunity for even broader interop! Just make the compiler parse any series of, say, 5+ consecutive !?,.+-[] characters not as a parse error but a Brainfuck expression! What could possibly go wrong?
Wrt the "_" and the ".", if those are documented at all, maybe make the other sections in the docs (eg the one on destructors) link back to there. I didn't read the docs from top to bottom, instead preferring to refer to them when I saw code I didn't understand. I bet I'm not the only one that likes to learn like that. Note that everything I write here is intended as a friendly suggestion and feel free to ignore all of it. I'm just a random guy from the internet.
Finally, wrt casting: I've always found that C-style "(type)" casts are weird and messy and don't fit the rest of the feel of the code. I wonder why you took them over? You also have "as" for dynamic-casting, and personally I think those are a lot more readable. Did you consider stealing some ideas from Kotlin and TypeScript wrt this to unify the two? Let me know if I'm stepping over a creative boundary here, but I'm personally quite mesmerized by Kotlin's !! operator[0], which simply forces a value to be not-null and throws otherwise. That's essentially what "(int)foo" does in Beef when foo can't be casted to an int, correct?
Then, if Beef had such an operator, then prefix casts would be semantically equivalent to "(foo as int)!!", right? Or maybe even the super-nice-on-the-eyes "foo as int!!" if precedence rules allow. Obviously a naive compilation of that would be slower (a dynamic cast followed by an if-null), but it seems like a pretty simple optimization to add.
Maybe "foo as .!!" could even be shortened to "foo!".
Given that you have int? and ?? and ?. already, I could imagine you considered something like this already and decided against it? Sorry for the rambling :)
Again, great job! Really looking forward to playing around with it more. Still totally blown away by the completeness of all this. I can't understand how a single person can pull all of this off on their own time.
I was a bit puzzled by the SDL2 wrapper by the way (SDL2.bf) - I can't find any place where it refers to a .lib or even a .dll file. How does this work? I tried to find a Visual Studio-esque "project settings" screen with deeply hidden list of .lib files but to no avail. How does Beef know where SDL is?
Performance-oriented implies a type of tradeoff made during design decisions - that tradeoff also means the language is weaker is certain ways than languages such as Javascript, Python, Ruby, etc.
Generally that would mean:
- More static, less dynamic
- No GC
- Lighter abstractions
- More directly conforms to hardware (even when it create a 'less clean' interface)
I'm guessing they were asking for some _specific_ features/techniques of Beef that contribute to achieving your design goal. The design goal itself is made very clear.
There's a lot of overlap ideologically. One major difference is that I'm an IDE fan and Jonathan dislikes IDEs. That can really percolate through a language.
BeefLang had an IDE on day one, and I think it'll show. One of my goals was to show how good a good IDE experience can actually be to someone who is used to working in C/C++.
> One of my goals was to show how good a good IDE experience can actually be to someone who is used to working in C/C++.
I wonder what you find lacking in the current C++ experience. e.g. with the IDE I use (QtCreator), I can quickly refactor things across million-lines codebases, perform a decent set of more advanced refactors (https://doc.qt.io/qtcreator/creator-editor-refactoring.html), auto-generate boilerplate code, I get in-line hints, lints and warnings while I type all with clang-based auto-completion...
personally I think the best IDE in the world is Visual Studio for C#.
I think Rust has the _potential_ to be better, but it's years off and requires the rust community to change how they think.
I'm interested in the IDE due to the authors claims, but I don't really see him making this IDE better than VS + C#. If he can, that would be amazing though.
> I think Rust has the _potential_ to be better, but it's years off and requires the rust community to change how they think.
The said change already happened and Rust devs are currently refactoring in depth their compiler to make it IDE-friendly (taking a lot of inspiration from Roslyn). This is tons of work though and even if it's currently going well, it won't be there before next year.
I've been learning and using Julia the last few weeks (coming from an OOP background). I highly recommend it. I mainly write highly mathematical programs and utilities to process some data or another. So far I've knocked out some smaller programs and started translating a larger library to learn about the type system. I haven't dug in to UI bindings yet.
My experience with Clojure was that you spend a lot of time looking at Java-level exceptions. It doesn't really hide the Java dependencies. It's an OK lisp if you want to combine it with Java, but if you don't... not so good.
Yup. And not necessarily a new Lisp - Common Lisp, with SBCL implementation, is plenty fast enough. It's just the library and tooling ecosystem that's lacking.
Why? SBCL implementation of Common Lisp is very usable for performance-oriented tasks; it compiles to native code, and with sufficient nudges, you can get pretty tight assembly out of it.
Clasp implementation of CL would be another choice, it leverages LLVM for compilation.
The problem is with the library and tooling ecosystem.
If you're going to do SIMD, you have to care about memory alignment. If you're going to do high-performance without SIMD, you still wind up caring about things like cache misses. So you'd want a Lisp that 1) lets you control memory alignment, and probably 2) that doesn't garbage collect. At that point, is it really a Lisp?
Now, you may say that "performance-oriented" doesn't have to go as far as SIMD or caching tweaks. And that's true. But if you want a performance-oriented language that can reach all the way up the performance curve, I don't see it being Lisp.
Depends on which parts of Lisp you're interested in. You can go as far as writing Lispy assembly (SBCL does), which gives you control over memory and is not garbage collected.
As someone desiring a performance-oriented Lisp, this is something I'd like. At runtime, I can handle memory myself ($deity knows I often do that when writing performant code). What I want to have is the friendly, homoiconic Lispy syntax, the ability (and the ease) to write code that writes code, and perhaps to have these facilities available at runtime.
Also, memory alignment isn't an entirely foreign concept to Lisp, it just rarely has been a focus. The long living irony that the etymology of the names of very common Lisp functions `car` and `cdr` themselves are a lingering artifact of 36-bit word memory alignment on an ancient IBM system architecture.
The code might be brilliant but the biggest obstacle to adoption is probably the name and the logo.
All I can think is "beef begins to smell after a couple of weeks" and it's hard to overlook that mental imagery when evaluating the vast array of good options in the programming language space.
It may also be considered culturally insensitive to a noticeable percentage of software engineers, which could hurt the adoption rate.
I'm a huge fan of C#, so this really caught my attention!
But I also have to say that the name logo are... offputting. I don't know why exactly; I'm not a vegetarian or religious or anything like that, and the name doesn't bring anything negative in particular to mind (hell, I love eating beef!), but it just feels... wrong somehow.
I am a carnivore, but the name rings pretty well for me. Beef is a simple food: it's not fancy and it doesn't need to be dressed up to be enjoyed. It's also enjoyable on a visceral level, and can hurt you if you're not careful with it. If this language lives up to promise it seems like it fits.
Not sure where you live, but in Europe beef is expensive, certainly "simple food" is not the first thing that springs to mind! I'm sure I've read somewhere it's one of the more expensive meats to produce, per kg, especially compared to chicken and pigs.
Just append " lang" when you Google it. And I'm pretty sure religious food prohibitions don't generally extend to using software that happens to share a name with the prohibited food.
This complaint makes the top 3 comments on every post about a new programming language. It's tiresome.
It's a bit more than that. I'm a vegetarian, so obviously I have a bias, but I think it's objectively true that the beef industry in America is in a pretty bad place. I consider it "horrific", personally, though reasonable people disagree.
Would "veal" be an acceptable name?
When I think of eating beef in 2020, I think of a person whose freedom to eat whatever pleases them is more important than human health, suffering of intelligent animals and the environment.
Allow me a bad analogy. If I interviewed someone for a senior engineering role but they went out of their way to mention that they had named one of their children "Stalin" -- that would be kind of a red flag for me.
So to me, naming your pet project "Beef" is kind-of tone deaf at best.
And at worst, it's thumbing your nose at political correctness: "Haha I named my project Beef because beef is great and fine and if you disagree you're thin-skinned and blindly following the crowd."
I think the issue is a lot more complicated than that.
I'm Vegan and the name doesn't bother me at all to be honest. I do not agree with the downvoting of parent though, as his reasoning is er.. reasonable.
Is it? Was the question about how acceptable would "veal" be as a name implying that it would not be acceptable at all? What about “lamb”? Or “pork”? (PORK is the long-awaited Well-Done BEEF, according to https://www.cs.cmu.edu/afs/cs/project/ozone/www/object-syste...)
Emphasis on notable percentage. That percentage is likely so small that it is easily enough to ignore. It is also not close enough to a "protected class" under USA law (and I assume many other countries too), that is totally fine in the legal sense to ignore those people for the purpose of programming language awareness.
> If the author does not consider it culturally insensitive, then there is no problem.
The author can do what he wants, but if he wants adoption, then it would behoove him to consider cultural sensitivity, especially if it is offensive to enough people to stifle adoption.
I would say that paragraph 2 is completely wrong. Why would you want to filter out people who are culturally sensitive from your community? Because you don't want to have to consider alternate viewpoints?
It would behoove the above poster to consider cultural sensitivity in selecting to use the word 'behoove', which contains 'hoove', which is a delicacy from cows in some cultures, as well.
And can I choose my own culture? Like say "this is what I endorse and believe in" and that be my culture? Or does this only apply to policically registered "-ism" classes (race, religion etc)?
If so, I belong to the culture that considers it insensitive to shit on things for light-hearted naming themes as if they are of any relevance next to a million other adoption metrics that are more objective, assuming the author even cares to weigh adoption vs creative license in the first place.
No one needs to "flip their shit" in order for it to be a bad name. I just don't like the sound of the word, for example, and that unpleasant feeling ends up tainting my opinion of the product.
If yes, then either you didn't care much in the first place, or you are indeed, flipping your shit.
And no one said it was a bad name, but that it could be considered culturally insensitive - two ambiguities away from actuallybeing the thing it mightconsidered to be.
You are almost certainly not eating animals to survive, you are doing it because you think it's normal and are either not aware that there is another way, or have chosen to ignore it. It is absolutely unnecessary for most people in first world countries to consume meat, there are easy to access alternatives that are better for the environment, animals, and quite possibly your health.
If you look at the screenshots it is clearly referencing dead animal flesh with the IDE icons.
"Eschew flamebait. Don't introduce flamewar topics unless you have something genuinely new to say. Avoid unrelated controversies and generic tangents."
If you find any proven cases where a vegan was inspired to start eating meat because of this name, I look forward to seeing your investigatory blog post.
All kidding aside, even if you are against the idea of being a carnivore, the name of a programming language does not promote such a thing.
A deep ethical concern for the treatment of animals is far older than computing: http://www.jewfaq.org/animals.htm . The cow is sacred to hindus, of which there are 1.08 billion.
stop assuming the problem is with people who care deeply about something and not people who tell them to shut up in public.
(Note: I'm not complaining about this in general, just giving my opinion based on the way I happen to do programming)
> which has been built hand-in-hand with its IDE environment
This is a red flag for me. What this implies is that the design of the language is likely heavily based on the expectatio that it will be used with the given IDE.
Basing a language on C and C# in 2020 seems like a very uninformed choice to me. Sure, C is a great language, and C# is very successful, so they must be good right? But I suspect that line of thinking is also what made the languages as successful as they ultimately became.
In a world where even javascript treats 0 as false, because it's what C did, whenever I see a programming language doing things "the C way", I just assume it's cargo cult language design, because most often that's what it is. That's not to say that there can't be good reasons for doing things the way C did them; after all, C did most of them for a good reason.
As for the C# part; other than it also falling into the cargo cult language category that copies C without understanding C, I don't really like it's idea of object orientation (which is really just javas idea of OO with a fresh coat of paint). What syntax it copied from C is acceptable, but tell me a modern language that doesn't have somewhat acceptable syntax. Even functional languages don't look like lisp anymore (except lisp itself, of course, which makes up for its inconvenient syntax with other advantages).
These are really bad reasons to not use a language.
Anyone who makes a language that is not like a popular language (ex
C or C#) should have to do a lot of justification for it, not the other way around. Change for change's sake is bad.
In other words, if you can make a language that does something new, without having to have new syntax or paradigms, that is much better.
> Anyone who makes a language that is not like a popular language (ex C or C#) should have to do a lot of justification for it
Of course; but that's expected. My point is that this always applies, but sometimes "C does it, so I'm doing it as well" is treated as a good reason for things when it really isn't.
Javascript, for example, treats 0 as false in if conditions. This made sense in C, which had no dedicated Nil-value and used the Nullpointer for that purpose, so 0 meant both the numerical zero and nil.
Javascript, however, has a dedicated nil-value, so 0 really only stands for the number zero, which isn't any less a value than any other number, and thus has way less reason to be treated as falsey.
So, in this example, while C had a good reason to do a thing, that reason just doesn't apply to JS. Maybe there are other good reasons that do apply to JS, maybe they just did what C did without thinking, maybe a bit of both.
But it does underline a opint: There should be a reasoning behind every language decision; one that specifically applies to the language in question. And I do believe this isn't the case with many C features.
Before Beef, I was developing game code in C# and engine code in C++ and I felt C# was just much more pleasant to work with - faster compile times, better IDE tooling, better errors, etc. Then it struck me that none of the things I liked about C# really had anything to do with the JIT or the GC, and it may be possible to create a "best of" merging between C# and C++.
I know there are other "C replacement" contenders out there - the differences are probably best explained through Beef's specific design goals listed at https://www.beeflang.org/docs/foreward/