using System;
class Program
{
public static void Main()
{
Console.WriteLine("Hello, World!");
}
}
// Try! propagates file and parsing errors down the call stack
static Result<void> Parse(StringView filePath, List<float> outValues)
{
var fs = scope FileStream();
Try!(fs.Open(filePath));
for (var lineResult in scope StreamReader(fs).Lines)
{
for (let elem in Try!(lineResult).Split(','))
outValues.Add(Try!(float.Parse(elem)));
}
return .Ok;
}
// Method returning a tuple
(float x, float y) GetCoords => (X, Y);
var tup = GetCoords;
if (tup != (0, 0))
Draw(tup.x, tup.y);
// Decompose tuple
var (x, y) = GetCoords;
Draw(x, y);
for (let i in 10...20)
Console.WriteLine($"Value: {i}");
let range = 1..<10;
Debug.Assert(range.Contains(3));
Span<int> GetLast10(List<int> list) => list[...^10];
// Allocate a string with a 4096-byte internal UTF8 buffer, all on the stack
var str = scope String(4096);
// String interpolation, formatting in 'x' and 'y' values
var str2 = scope $"x:{x} y:{y}";
// Create a view into str2 without the first and last character
StringView sv = str2[1...^1];
// Get a pointer to a null-terminated C string
char8* strPtr = str2;
enum Shape
{
case None;
case Square(int x, int y, int width, int height);
case Circle(int x, int y, int radius);
}
Shape drawShape = .Circle(10, 20, 5);
switch (drawShape)
{
case .Circle(0, 0, ?):
HandleCircleAtOrigin();
case .Circle(let x, let y, let radius):
HandleCircle(x, y, radius);
default:
}
if (drawShape case .Square)
HandleSquare();
// This class uses 'append' allocations, which allows a single "batch"
// allocation which can accomodate the size of the 'Record' object, the
// 'mName' String (including character data), and the 'mList' list,
// including storage for up to 'count' number of ints
class Record
{
public String mName;
public List<int> mList;
[AllowAppend]
public this(StringView name, int count)
{
var nameStr = append String(name);
var list = append List<int>(count);
mName = nameStr;
mList = list;
}
}
// The following line results in a single allocation of 80080 bytes
var record = new Record("Record name", 10000);
[CRepr]
struct FileInfo
{
c_short version;
c_long size;
c_char[256] path;
}
/* Link to external C++ library method */
[CallingConvention(.Cdecl), LinkName(.CPP)]
extern c_long GetFileHash(FileInfo fileInfo);
/* Import optional dynamic method - may be null */
[Import("Optional.dll"), LinkName("Optional_GetVersion")]
static function int32 (char8* args) GetOptionalVersion;
void Serialize(SerializeContext ctx, Object obj)
{
for (let field in obj.GetType().GetFields())
{
Variant v = field.GetValue(obj);
ctx.Serialize(field.Name, v);
if (let attr = field.GetCustomAttribute<OnSerializeAttribute>())
{
var m = attr.mSerializeType.GetMethod("SerializeField").Value;
m.Invoke(null, obj, field);
}
}
}
static mixin Inc(var val)
{
if (val == null)
return false;
(*val)++;
}
static bool Inc3(int* a, int* b, int* c)
{
// "return false" from mixin is injected into the Inc3 callsite
Inc!(a);
Inc!(b);
Inc!(c);
return true;
}
// Declare List<T>.DisposeAll() for all disposable types
namespace System.Collections
{
extension List<T> where T : IDisposable
{
public void DiposeAll()
{
for (var val in this)
val.Dispose();
}
}
}
static int32 Factorial(int32 n) => n <= 1 ? 1 : (n * Factorial(n - 1));
const int fac = Factorial(8); // Evaluates to 40320 at compile-time
public static Span<int32> GetSorted(String numList)
{
List<int32> list = scope .();
for (var sv in numList.Split(','))
list.Add(int32.Parse(sv..Trim()));
return list..Sort();
}
const int32[?] iArr = GetSorted("8, 1, 3, 7"); // Results in int32[4](1, 3, 7, 8)
// Create serialization method at compile-time on types with [Serialize]
// No runtime reflection required
[AttributeUsage(.Types)]
struct SerializableAttribute : Attribute, IComptimeTypeApply
{
[Comptime]
public void ApplyToType(Type type)
{
let code = scope String();
code.Append("void ISerializable.Serialize(SerializationContext ctx)\n{");
for (let field in type.GetFields())
code.AppendF($"\n\tctx.Serialize(\"{field.Name}\", {field.Name});");
code.Append($"\n}");
Compiler.EmitAddInterface(type, typeof(ISerializable));
Compiler.EmitTypeBody(type, code);
}
}
Custom IDE
The Beef Development Tools include an IDE with a general-purpose debugger capable of debugging native applications written in any language.
Productivity Features
The IDE supports productivity features such as autocomplete, fixits, reformatting, refactoring tools, type inspection, hot compilation, and a built-in profiler.
Mixed Builds
Beef allows for safely mixing different optimization levels on a per-type or per-method level, allowing for performance-critical code to be executed at maximum speed without affecting debuggability of the rest of the application.
Real-time Leak Detection
Beef can detect memory leaks in real-time. As with most safety features in Beef, this can be turned off in Release builds for performance-critical applications.