jemc changed the topic of #ponylang to: Welcome! Please check out our Code of Conduct => https://github.com/ponylang/ponyc/blob/master/CODE_OF_CONDUCT.md | Public IRC logs are available => http://irclog.whitequark.org/ponylang | Please consider participating in our mailing lists => https://pony.groups.io/g/pony
autodidaddict has quit [Quit: Page closed]
amclain has quit [Quit: Leaving]
Praetonus has quit [Quit: Leaving]
aceluck has joined #ponylang
<aceluck> Hi all, quick question - I'm doing some c ffi stuff, and getting back a string pointer, so I use String.from_cstring(p) - which gives me a ref. What I'd like though, is an immutable string. I can't seem to wrap it in recover val either, because the p is not sendable
<aceluck> (p has to be a ref according to the String api)
<jemc> aceluck: without knowing anything else about your surrounding code, your best bet is to get the pointer from FFI as a `Pointer[U8] iso` instead of a `Pointer[U8] ref`
<jemc> an `iso` reference can pass into a `recover` block, and it can be `consume`d to give to the String constructor
<jemc> that is, with `String.from_cstring(consume p)`
<aceluck> Even with consume p I get the error iso! is not a subcap of ref
<aceluck> My mistake... the p was indeed an iso!
<aceluck> @jemc: Thanks
<aceluck> I had to get it as Pointer[U8] iso^ so as not to make it an iso!
<aceluck> It does segfault though :)
<jemc> ah, sorry about forgetting the `^` part
<aceluck> Could consuming the p cause the garbage collector to free the pointer? Cause now I'm getting a segmentation fault - but it's not happening straight away
<jemc> aceluck: the `consume` melts away at compile time, so it wouldn't cause any garbage collection
<jemc> however, it's definitely possible that some aspect of your FFI pointer managment is going poorly for you
<aceluck> It works well when I pass p as ref though. But then I have to clone() the string to make it read only. Which is an okay workaround, except that it feels wrong and might impact performance
<jemc> is it possible that the C library is deallocating the pointer on you?
<jemc> clone does a copy of the data into a new pointer "owned by Pony"
<jemc> what call in what C library are you getting your pointer from?
<aceluck> This did the trick: recover val
<aceluck> String.from_cstring(@__gmpz_get_str[CPointer ref^](None, base, t))
<aceluck> end
<aceluck> I'm not storing the ref and passing into the recover block, but sending it without aliasing
<aceluck> It's libgmp
dtzWill has quit [Ping timeout: 240 seconds]
<jemc> that shouldn't affect anything related to GC though... :/
<jemc> in fact the generated code should be pretty much equivalent as you doing the FFI call just outside the recover block and assigning to an iso
<aceluck> Yeah.... Also, it didn't "do the trick". When I compiled again, I got a segfault. Another recompile, and it was fine, another I got a fault and so on.
jemc has quit [Ping timeout: 260 seconds]
jemc has joined #ponylang
<jemc> aceluck: I'd suggest trying the other approach for string allocation in the gmp library - supplying your own string
<jemc> figure out how big of a string to allocate, using the `mpz_sizeinbase (op, base) + 2` method recommended by the gmp docs, then do something like:
<jemc> `recover let buf = String(buf_size); @__gmpz_get_str[CPointer tag](buf.cpointer(), base, t); buf end`
<jemc> that will let you end up with a pointer that is Pony-managed, but without the unnecessary allocate-and-copy
<doublec> It's possible the segfault is due to some other ffi usage. Your usage in that case does look fine.
<doublec> I assume Pony uses 'free' to free the String memory
<jemc> yeah, I suspect that either pattern should be fine, but the pattern I suggested of letting pony allocate the pointer means you won't have to track it and free it yourself later
<aceluck> Do I then make the string from the buf or the returned pointer?
<jemc> doublec: no, Pony has its own alloc and free methods that go to a pool
<jemc> aceluck: the buf is your string already - ignore the returned pointer
<doublec> jemc: but if the pointer is from ffi it should be free'd when the String object is finalized shouldn't it?
<doublec> Oh I see - is the reason for the segfault that Pony attempts to free it?
<doublec> and it was malloc'd instead of using pony_alloc?
<doublec> the help for from_cstring says to only use it for arrays that were pony_alloc'd
<aceluck> I have a few attempts in that file - fromBase2 is the one using pony alloc. But the buffer doesn't become the string for some reason. However, if I initialize from the pointer returned, I get a result
<doublec> aceluck: I think the String needs to be sized as gmpz_sizeinbase + 2
<doublec> aceluck: to account for sign and null character.
<aceluck> Ah yes, true. Still same result though :/
<jemc> aceluck: can you update the gist with your changes?
<doublec> aceluck: fromBase2 seems to work for me
<doublec> aceluck: If I uncomment the "let s2" and return "s2"
<jemc> doublec: but it should be working for returning buf
<aceluck> Yes, that's what's odd
<doublec> ah I see
<doublec> So the constructor for String only reserves the space, the length of the string is still zero
<doublec> Nothing updates that length
<jemc> yeah, I forgot that this was the case
<jemc> this works, but it ain't pretty:
<jemc> `let buf = String.from_array(recover Array[U8].init(0, size) end)`
<doublec> Another option would be to set the default libgmp allocator to be pony_alloc.
<doublec> Oh, I guess getting the pony_ctx to that might be hard.
<jemc> haven't looked the the libgmp API, but `pony_alloc` requires a `pony_ctx`
<jemc> yeah
<aceluck> Oddly, with that solution I need to take away the +2 size or the string will be too long
<jemc> however, as I did in my link, you can get the `pony_ctx` using an argument-free FFI call
<jemc> so it may not be that big of a problem, assuming the libgmp allocations all happen in the same thread that you call them from
<aceluck> Actually this works fine: fun fromBase(base: ISize) : String ref^ =>
<aceluck> let p : CPointer = @__gmpz_get_str[CPointer](None, base, npointer)
<aceluck> String.from_cstring(p)
<aceluck> Except it returns a string ref^ which I can't print
<aceluck> or send
<aceluck> It looks nicer though
<jemc> aceluck: it's still going to have the same GC issue - it will have problems when Pony garbage-collects the String
<aceluck> Right
<aceluck> I've updated the gist with the working solution
<aceluck> Thanks guys
<jemc> aceluck: do you want me to try to rig up doublec's suggestion using custom allocation feature of libgmp?
<aceluck> That might be nicer
<aceluck> As other functions down the line might allocate
<jemc> with your `iso^` code that was seeing the segaults
<aceluck> Is there a trick where an init method on a primitive will be run once and once only?
<jemc> `_init` is a special method name - define it on a primitive and it will work as you describe - will be run once before your Main actor begins
<aceluck> Excellent. It works now with the custom alloc
<aceluck> It now reduces to a oneliner: recover val
<aceluck> end
<aceluck> String.from_cstring(@__gmpz_get_str[CPointer ref^](None, base, npointer))
<jemc> :tada:
<jemc> sorry it took me so long to recall the lessons I learned in implementing pony-sodium :#
<jemc> so we've seen a lot of folks come through here working on libgmp bindings for Pony - will you be the one to pull the sword from the stone?
bitcrusher has joined #ponylang
<aceluck> I actually just needed divmod to do base58 encoding, but I'll try to find the time
<aceluck> Actually I think a port would be better. gmp is a mess
jemc has quit [Ping timeout: 240 seconds]
vaninwagen has joined #ponylang
aceluck has quit [Quit: Textual IRC Client: www.textualapp.com]
papey_lap has joined #ponylang
vaninwagen_ has joined #ponylang
vaninwagen has quit [Ping timeout: 240 seconds]
Candle has quit [Ping timeout: 258 seconds]
carado has joined #ponylang
<carado> hi, i'm trying to build to release branch of ponyc and i get the single error "src/libponyc/type/typeparam.c:606:5: error: this statement may fall through", should i just remove -Werror from the Makefile ?
<carado> (i've heard bad things about -Werror in release building)
samuell has joined #ponylang
<carado> (yeah that and specifying CC= worked nevermind)
papey_la1 has joined #ponylang
papey_lap has quit [Ping timeout: 268 seconds]
SimonJF has joined #ponylang
Candle has joined #ponylang
Candle has quit [Ping timeout: 240 seconds]
Candle has joined #ponylang
vaninwagen_ has quit [Ping timeout: 276 seconds]
_andre has joined #ponylang
autodidaddict has joined #ponylang
papey_la1 is now known as papey
<autodidaddict> would love thoughts/feedback on this post before I publish it: https://medium.com/@KevinHoffman/rolling-the-dice-with-pony-b7a32a69267b
<shepheb> in "All functions on a class are actually receivers." I would say methods, not receivers.
<shepheb> "this" is the receiver, foo() is the method.
<shepheb> content LGTM
<shepheb> looks good to me, sorry. I always forget that's mostly a Googlism.
<shepheb> on another subject, the C FFI parts of the tutorial would perhaps do well to give an example of turning a Pointer[A] from C code into a Pony array.
<autodidaddict> good points. I'll make some edits. thanks
<shepheb> it wasn't hard to piece that together from the documentation for arrays, but still.
<shepheb> (context is getting a void* from SDL_LockTexture that I need to populate)
<autodidaddict> I figured LGTM was pretty mainstream
<shepheb> that's what I thought, having seen it myself before joining Google. but then I routinely find people puzzled by it, so I expand it now.
jemc has joined #ponylang
<shepheb> \o/ my Gameboy emulator is now rendering something.
<shepheb> it's a bit broken, but it's rendering something.
obadz has quit [Ping timeout: 240 seconds]
obadz has joined #ponylang
<autodidaddict> that's awesome
<shepheb> looking forward to sharing this code, but it's not interesting when you get a hollow window frame and can't run any software on it.
<autodidaddict> those are the inspiring moments... when you know your building blocks are there and working. That's when the fun starts :D
<jemc> carado: can you file an issue ticket about the fall through warning? we should fix it
<jemc> shepheb: exciting!
<shepheb> there, found the rendering bug. it's rendering a really basic scene competently.
<jemc> shepheb: screenshot?
<shepheb> :)
<shepheb> the junk characters aren't intended, but they show up in a released emulator too, so I guess it's a bug in my test app.
<shepheb> next is running a test app that exercises the CPU, and looking for any bugs.
amclain has joined #ponylang
<autodidaddict> nice
aceluck has joined #ponylang
obadz has quit [Ping timeout: 246 seconds]
obadz has joined #ponylang
samuell has quit [Quit: Hejdå]
papey_lap has joined #ponylang
papey has quit [Ping timeout: 268 seconds]
bimawa has quit [Quit: WeeChat 1.4]
<aceluck> Hi - I'm doing some ffi stuff, and it's crashing, and I'm trying to narrow it down. However, scattering print statements throughout the code doesn't work when the output streams are async. Is there a way to do synchronous output?
<jemc> aceluck: check out the `debug` package, which provides a `Debug` primitive that wraps a synchronous C call to print a debug statement
<aceluck> Thanks
<jemc> it's cheating on the ambient authority principle a bit, but it's only present in `--debug` builds, and it's really darn useful
<aceluck> I'll only use it temporarily, promise ;)
<aceluck> Doing ffi - if I need to pass a **void so that I can get back a pointer to some opaque structure - do I pass in addressof a Pointer[U8] or..?
<jemc> yeah, I'd probably do `addressof` on a `Pointer[None]`
<jemc> IIRC there's also another trick where for an opaque object you can make a `class` with no fields, and use that instead of the `Pointer[None]`
<aceluck> Okay cool
<jemc> let me make sure I'm remembering that right though
<jemc> ah, not quite right
<jemc> the idea was to make a primitive, and use `Pointer[MyPrimitive]` instead of `Pointer[None]`
<aceluck> Hmm... it needs to be dynamic though
<jemc> aceluck: it still can be - you never unwrap the pointer
<aceluck> Primitive works fine if there's only one I suppose
<aceluck> ... not sure I follow
<jemc> you're not using it like a real primitive, you're just using it as a type system trick so you can distinguish one FFI pointer type from another
<aceluck> Ah I see :)
_andre has quit [Quit: leaving]
<aceluck> Found my segfault - I'd passed None instead of Pointer[None] somewhere I meant to pass a nullpointer
<jemc> yeah, debugging FFI usage can be tricky - in any otherwise memory-safe language, not just Pony
<jemc> that's one big reason to want to isolate your FFI usage to just a handful of packages that wrap the FFI interface in an idiomatic Pony one
<aceluck> Indeed. Ironically, I started using pony to avoid that kind of trouble :)
<jemc> sounds like it's time to start on your libgmp port then :D
<aceluck> But yes, once it's wrapped up nicely, it'll be sweet
autodidaddict has quit [Ping timeout: 260 seconds]
papey_lap has quit [Ping timeout: 240 seconds]
<aceluck> Why does Array.from_cpointer require a ref to the pointer?
<jemc> aceluck: because the `Array` it creates is also a `ref`
<aceluck> How do I make a read only copy of an array?
<aceluck> I keep banging my head here. from_cpointer requires a ref, so the resulting array is a ref. If I copy it, copy_to also needs a ref. There's no way to get from ref to val, because I can't recover the original pointer. Argh
<jemc> aceluck: I think you need the same pattern I suggested yesterday - if you use an `iso` for the original pointer, it can pass into the `recover` block (because it is sendable), and from there you can consume it to "drop down" to `ref` for the argument of `Array.from_cpointer`