New Buoy releases

for future releases, they’re going to be posted on the buoy-issues repo.

NOTE: There’s now an Intel build of Buoy for macOS available. Internal tests show that all of the example projects compile just fine on Intel.

NOTE 2: The Mac builds are now notarized.

I’ve been working on setting things up today to make it easier to do releases and a couple of features have snuck in along the way. Still working out why they’re not appearing on the releases page…

0.4.4

New Items

  • Added c# “partial classes” so class definitions can now span across separate files.
  • Added VSCode “Run File” command with a Play button in the editor title bar and context menu for bui files.
  • Added VSCode buoy.compiler.path setting to specify a custom compiler binary path.
  • VSCode LSP module is now a universal binary.

Fixes

  • macOS builds of buoy are now signed and notarized
  • fixed a few examples that were using reserved words for class names

In case you didn’t see it, we’re up to 0.6.1

Keep in mind that the VSCode extension is being updated with every release and is getting better and better in terms of autocomplete and other features so don’t forget to update that too!

Buoy 0.12.1

Changes since 0.6.1

New

  • The Buoy Language Server is now available as an MCP server

  • Add Timer class

  • More work on the VSCode Extension

  • Add nested enums

  • Namespaces

  • feat: Structures may now be placed inside classes

  • feat: Enums can now be embedded in structures

  • feat: make it so modules can be embedded in packages, which ultimately lets us create controls

  • feat: add some more compiler directives. TargetDesktop, TargetConsole and TargetLibrary feat: if unspecified, the compiler now attempts to auto-detect if an app is a desktop or a console app so TargetDesktop and TargetConsole can be set correctly.

  • feat: Added a class for dealing with JSON.

  • feat: Added BinaryStream, TextInputStream, TextOutputStream

  • feat: Added Bytes class for dealing with raw data

  • feat: Added HTMLView

  • feat: add Int8, UInt8, UInt32 and UInt64

Bugs

  • fix: fix a compile crash for Select Case with a string variable that’s inside a method

  • fix: bug fixes

  • fix: fix enum and struct scoping inside a class

  • fix: fixed an issue where if the LSP needed to guess what to do with an open #if statement, it would always choose mac/arm. Now it will choose the platform/cpu combination of the LSP.

  • fix: fixed a frontend compiler bug that caused autocompletion failures in LSP and therefore VSCode

  • fix: add icon and readme to the vscode extension

  • fix: Bytes now throws an OutOfBoundsException if you try to access something outside instead of crashing

  • fix: rewrote lsp caching code

  • fix: Autocomplete now works in VSCode for projects that are not in the buoy directory

  • fix: the run command in VSCode now correctly detects when the project was built as an app bundle

  • fix: linker no longer points at files on a developer machine

  • fix: LSP now gets its word list from the token list

Buoy 0.13.1

Low feature count today. Drag-and-Drop was a beast! Got the basic controls hooked up and Listbox will get its chance soon!

New

  • Now using dmg for macOS distribution

  • Drag and drop is now available on Canvas, Label, TextField, TextArea, PagePanel, TabPanel, ImageView and View

Fixes

  • strings are now initialized with “”

  • Strings stored in records and arrays are now initialized with “”

  • Standardized the macOS minimum deploy target across all libraries

Buoy 0.14.0

New

  • Added a comprehensive tutorial on how to create packages

Fixes

  • fix: When building a buipkg, the compiler will now automatically create a manifest to help buipkg developers generate correctly formatted packages

  • fix: Fixed a few buipkg bugs that showed up on unit tests

  • fix: make it so the package loader looks in the link folder first and then moves to the runtime because on macOS and Linux, the files may be the same. Doing this makes packages ~32% smaller.

  • fix: added an option to buoy for specifying the install name when building a library. This is specifically for adding @rpath

  • fix: When libraries are built with buoy, we no longer just overwrite the header that’s there. The compiler is now smart enough to combine the declares into groups as necessary with #if pragmas.

  • fix: When building buoy libraries for a package there’s now a new option named “–emit-declares” which will also create a .bui file containing the declares for accessing each of the public methods that’s needed for the packaging process.

I fail to discover the original announcement for this product. What is it about?

Here is the message that started it

Was there some example yet on how to wrap a existing C++ dylib (similar to how you did with the Sqlite I guess)

Thanks

Björn

Yes. The 0.14.0 release was all about packages and many improvements came with that release including a tutorial in the docs folder. Technically you should be able to do controls, but I have not tried that yet. nor have I exercised the delegate and declare system much. There’s no support for obj-c blocks yet but that’s on the sooner rather than later path.

I value your input here Björn. I’m sure you and Christian will have a lot of input on how packaging should evolve.

For now, they come in three types:

  1. Buoy source - purely source code, just for sharing.
  2. Buoy source, compiled to dylib, DLL, so
  3. 3rd Party C++, compiled to dylib, DLL and so

I’m certainly open to more forms if we needed something like a completely binary format with a more predefined contract. I just haven’t had a use for that yet.

I would just start with something with low dependencies, as in not control. Maybe MS Word Reader / Writer. (or something like that that is just basically file and string, and I would just skip image support for now to have like least resistance test)

So I would take my C++ code and adapt it so there is no REALstring in it. And make Dylib I guess. And presumably I make then some Buoy around it to make nice interface that talks with Buoy String and something for FolderItem (Ihave not checked what that is in Buoy).

Am I understanding this correct ?

Or will it be the dylib is somehow made just ready for Buoy with correct types and no need for Buoy also to wrap it into nice types ?

Note that i do not want to rush you in anything, there are many things that are far more important at the moment in getting things up and your doing great job at it.

Exactly. It’s just libs with exported methods and a Buoy file filled with declares at the moment.

All strings are UTF8 right now and it will be the default in the future.

FYI - I’m striving to make sure there’s always a way to get to the underlying object through a pointer when appropriate although the buoy property names have not been very consistent so far and I need to nail that down.

A few questions about strings.

In .NET strings are UTF16 internally probably because of Windows historical reasons. You can output as UTF8 or whatever of course. They are also immutable for thread safety reasons and though they have value semantics they are heap objects and can be null. Strings have a char indexer and can be converted to a char[] and back, though in recent times that is usually done via [ReadOnly]Span, which gives you safe copy semantics, etc.

In Objo they are advertised as UTF8 but I am suspicious they are backed by .NET strings and so are UTF16 internally and just output as UTF8. So that means on average 2 bytes per char, even for the ASCII domain, in terms of memory consumption. This isn’t fatal of course, I live professionally in the C# world and am used to it.

I don’t know what REALstrings are and probably don’t want to know, lol.

But my paying work involves LOTS of detailed string manipulation on hot paths and I’ve evolved a whole ecosystem around making that as performant as possible. So to my specific questions:

Are Buoy strings in memory, internally, literally UTF8, that is, code points < 128 take exactly one byte in memory

Are they immutable

Do you or will you expose a char type and what relationship exactly will that have to Buoy strings. Can you at least read the char in position 7 of a string in some form other than another string instance of length 1?

What support do you or will you have for operating in the char or code point domain in preference to the allocation pressure of [sub]string concatenation, etc. when the extra effort makes sense because of hot paths? In other words would you have something like the .NET StringBuilder or some other form of mutable string manipulation. So if you want to convert a string to some char-oriented representation, then say trim it, upper case it, append some other string to it, then convert it back to an immutable string, can that be done at this time? Even if I have to roll it myself?

IIRC Buoy objects, including strings, are reference counted. I am less familiar with the performance implications of allocating a lot of strings in a reference counted vs garbage collected environment, aside from memory consumption. The garbage collector isn’t there to overwhelm, but you still need some kind of circular reference detector process I would assume and still have to deal with memory fragmentation issues. Would you regard my concerns as less relevant in a reference counting system? More? The same?

Thanks

Yes

Yes

can you give me an example of a form other than string?

That’s a lot. For a project that isn’t even 1.0 yet, I honestly haven’t considered this. More encodings are high on my list however. I know that’s not much of an answer but I just don’t have an answer for this yet.

There’s a way to compile apps in such a way that you’ll be informed of memory leaks when the app quits. Can’t remember off the top of my head because so much has been implemented since then. If buoy —help doesn’t give you a clue, I’ll have to look it up.

That’s fair.

The basic idea is to not create a welter of string allocations when parsing.

For example if I need to read character by character because of parsing requirements (or you could say, code point by code point) I might run the char stream (not a byte stream as char <> byte) through a finite state machine because I’m, say, reading a CSV file that has embedded line endings in some fields (because they’re multi-line text fields, say). I might want to look ahead when I see a line feed to see if there’s a carriage return after it, so I can handle that situation. In any case I can’t just burst a string on commas. I have to handle quoted strings, strings containing escaped quotes or line endings or form feeds, that kind of thing.

So it’s basically a need to operate in the domain of code points or some proxy like a char type at times. Also the need to assemble a new string from slices of other strings without every intermediate step resulting in another string. That is conceptually easier and fine in a lot of situations but not cool on a hot path. In .NET it will put a lot of pressure on the garbage collector, but also, if say you can only access the nth character of a string as another string, in 64 bit systems on .NET at least that’s 22 bytes of memory to represent what a char would usually be able to represent in 1 or 2 bytes. Objects have overhead – heap pointers, plus internal housekeeping. They aren’t particularly lightweight. Spinning up a new string as a side effect of mutability is expensive on hot paths. Etc.

Just something to hold back-of-mind for now, and I suppose if you have a robust interop with external code the need to deal with it is less. It’s not like this is top of mind for a lot of use cases, it is just my weird little specialist world.

Let me put this idea forward. There’s enough language structure here to start doing some real-world tests between X and Buoy. For instance, on my M5 MacBook, the following code runs as a console on both machines (minus the sub main() part for X)

sub main()
  Dim t As Double = DateTime.Now.SecondsFrom1970
  Dim u As Double
  print str(t)

  For i As Integer = 0 To 100000000

        //

  Next i

  u = DateTime.Now.SecondsFrom1970
  Print Str(u)
  print str(u-t)

End Sub

X reports 3.9 seconds

Buoy reports 0.0. In fact, I had to add two more zeros to get it to show anything and at that point it said 3.

That could very well mean that the Buoy framework is currently 130x faster than X at simple counting. We’ll have to do many more experiments to find out over the coming weeks as Buoy continues to evolve, but if string operations are even half as fast, you still may not care.

*Buoy was compiled with no optimization enabled, Xojo was set to “Default”

That is a poor benchmark as compiler can just optimize the loop away as it does nothing.

In real world performance terms a fast compiler can only do so much. It can’t overcome I/O or network bottlenecks or inefficient data structures all by itself. It is still allocating a string vs a char and strings are still immutable (optimized for concurrency) so doing everything in the string domain is always going to be relatively inefficient no matter the compiler. You would see the difference parsing a 100,000 record file in C# even if using AOT (native code compilation rather than bytecode). You would not see the difference doing some small-time string concatenation that’s not on a hot path, of course.

This is why I asked about reference counting vs garbage collection. I suspect a GC is contributing to the difference I am seeing in that garbage-collected environment, although even that isn’t the factor it used to be; .NET has largely optimized away the “stop the world” garbage collection approach.

Except that it didn’t. Just by increasing the number of loop iterations, I did get a result.