Hello!
I was recently encouraged by a friend to try out Odin.
This weekend I decided to try it out by writing a Lua parser.
The result can be found here: GitHub - ManuelBlanc/lua-parser.
It has been very pleasant to work in and I’m looking forward to using it more.
I have two unrelated questions:
(1) What is the rationale behind or_else
being left-associative?
// Have not had a real need, but seems useful with maps:
val := map0[k] or_else (map1[k] or_else .None)
When trying the feature, bare chaining was the first thing I tried and was surprised it did not work. Parentheses do not feel very ergonomic. A message from 2024 in Discord mentions chaining is discouraged. Why is this?
(2) What is an idiomatic way to prevent struct member access from other files/packages?
In other words, the equivalent of the C idiom:
typedef struct My_Struct* My_Struct;
.
I tried these approaches but was not satisfied:
@(private="file")
Internal :: struct { m: int }
Public_0 :: struct { using Internal } // Does not work.
Public_1 :: ^Internal // Does not work.
Public_2 :: distinct uintptr // Works, but messy and adds boilerplate.
Is there a better way?
1 Like
(1) For clarity of reading. Forcing the parentheses around the right-hand-side makes it clearer which is for which. But I highly recommend against doing this in the first place. This is usually a sign of doing something bad.
(2) There isn’t an “idiomatic” way. It highly depends on the problem that you are doing. Opaque data structures which must be a pointer are sometimes better treated as just Handle :: distinct rawptr
, but sometimes better treated as Foo :: struct { using _: _Foo }
or whatever.
Hey gingerBill,
appreciate you taking the time to reply and thanks for the hard work on Odin.
(1) There is a single valid parse tree so I’m not sure I see the clarity gain.
I understand that this is subjective. I’d like to pick your brains on this matter not to argue, but to learn. How is it a sign of doing something bad?
(2) The goal is reduction of API surface area. This is based on my personal experience that if an internal symbol is publicly visible it tends to eventually be used externally.
I could not get the second suggestion to work. Using a rawptr
handle does the job but requires a bit of boilerplate unlike the C++ idiom. This is a price I’m willing to pay. Using a parapoly made it more palatable:
Pointer_Box :: struct($T: typeid) {
ptr: rawptr,
}
unbox :: proc(b: Pointer_Box($T)) -> ^T {
return cast(^T)b.ptr
}
box :: proc(ptr: ^$T) -> Pointer_Box(T) {
return Pointer_Box(T) { ptr }
}
On a side note, I found surprising that a pointer to a struct marked @(private)
allow accessing the fields. I now understand only the type name itself is private and had wished for some kind of “incomplete” type as in C/C++.
Cheers & thanks again// Manny
(1) clarity for others to read, not just yourself
(2) don’t do boxed pointers. That’s a really bad idea.
(2a) fields in Odin don’t have any public/private aspects to them on purpose. I absolutely hate private
/protected
in C++ with a passion and find it the wrong construct pretty much always.
1 Like