-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Sorry to take so long on the FFI fixes. It's unfamiliar code, so when working out new code it's best to get them nailed down with familiar code for starters.
First a heads-up on what's changed. It used to be that the [0] element of an object's "varlist" was a FRAME! data type that helped in navigate to the second series, the "keylist". This FRAME! datatype was tricky and internal, never meant to be seen by users (and if they did it was likely a bug). But what it allowed one to do was to use a single platform pointer to effectively pass around a whole object, that you could later reconstitute with just Val_Init_Object(&value, frame).
There were a number of drawbacks to that, including that if you had a frame for some other context type (such as an ERROR!, PORT!, or MODULE!) that information was lost. So a lot of code that would extract a frame and pass it around, to later be given to the user, would come back with an object.
>> port: open %foo.txt
>> probe port
make port! [ ; << here, it's a PORT!
spec: make object! [
title: "File Access"
scheme: 'file
ref: %foo.txt
path: none
]
...
>> words: [spec]
>> bind words port
>> bind? first words-of port
== make object! [ ; << now, it's an OBJECT! :-/
spec: make object! [
title: "File Access"
scheme: 'file
ref: %foo.txt
path: none
]
...
It was a bit convoluted, introduced a new type the user shouldn't see, and wasn't adaptive to things like if the various context types had the struct fields in the cell change. So the better idea seemed like to put in each paramlist a canon instance of the value itself. Hence the [0] would be an OBJECT! if it were an object, a PORT! if it were a port, ERROR! if an error, etc. If you wanted to get a copy of that value back, you'd just copy out of that position.
This same thing seemed to be applicable to functions...so it was applied there as well. The [0] slot in the paramlist was no longer unused, but a value of that function. This made it easier to pass functions around by just a pointer and get the whole value back.
That helps some in the FFI where previously it had been necessary to work a bit harder to pass a function around by its payload:
Line 1064 in 29f7bbf
| REBFCN func; |
Line 924 in 29f7bbf
| } REBFCN; |
Now it doesn't have to, one pointer will do:
The mistake I made (or at least one) when taking the "all you need is the one pointer" mentality to the FFI was that I didn't extract the whole value to reconstitute it. I replaced the line for filling in the whole payload with something that effectively only filled in the paramlist. The right answer is to copy out that value from slot 0 in its entirety:
Note that should also mean you could use a callback that was a closure (for instance), because it would get back the right type. (CLOSURE! is being expired and FUNCTION! is being fixed, but the point is still relevant...it's parallel to the issue about PORT! and OBJECT! above.)
Anyway, that actually seemed to be the only thing going wrong in the %qsort.r and %gtk.r cases. So let me know if there's anything else.
Other issues:
- The WRITABLE bit is now checked in debug builds. This means it's possible to make any value you want read-only as far as a debug build is concerned, but it also means that to make a REBVAL slot writable you have to "format it" for writing. That's done in series automatically, but if you create a REBVAL on the stack you have to use
VAL_INIT_WRITABLE_DEBUG(&value);on it before you can write to it. Due to randomness of stack memory, you may or may not be warned about it if you forget...though you'll be warned more often than not, since a zero bit in the least significant position means "read only". - Let me know if you feel there's still something worthwhile to be learned from the Ren-C Split branch. If you're able to link up the GUI now then it's old news and out of date...so if I can let it go then that keeps the number of things I look at in lists every day down by one. :-)
- Rebol Debugging! A start at it, anyway...