plietar has quit [Remote host closed the connection]
plietar has joined #ponylang
plietar has quit [Remote host closed the connection]
plietar has joined #ponylang
plietar has quit [Remote host closed the connection]
plietar has joined #ponylang
plietar has quit [Read error: Connection reset by peer]
plietar has joined #ponylang
samuell has joined #ponylang
plietar has quit [Remote host closed the connection]
plietar has joined #ponylang
plietar has quit [Ping timeout: 255 seconds]
plietar has joined #ponylang
plietar has quit [Ping timeout: 246 seconds]
plietar has joined #ponylang
plietar has quit [Ping timeout: 255 seconds]
bimawa has quit [Quit: WeeChat 1.9]
theodus has joined #ponylang
theodus is now known as theodus_
Praetonus has joined #ponylang
_andre has joined #ponylang
ro6 has joined #ponylang
<ro6>
I'm getting a strange error when using "_" to ignore part of a tuple in a match expression, "cannot capture "_", variable not defined"
<ro6>
I've tried to minimally reproduce, but can't get the error with smaller cases
<ro6>
I replaced occurrences of "_" in the tuple with "let _: MyType" and it compiles again
Matthias247 has joined #ponylang
_etc has joined #ponylang
<SeanTAllen>
what was the code you had previously before the "it compiles again" ro6?
<SeanTAllen>
sounds like you changed 1 line to get it to work, yes?
<ro6>
(_, let myCapture: MyType) doesn't compile (let _: MyType, let myCapture: MyType) does
<ro6>
I'm simplifying because the actual code is in the middle of a much larger program, and I can't get a smaller reproduction to trigger the error
<ro6>
my intention is to ignore several values in a tuple I'm matching against, and I'm surprised the compiler sees "_" and tries to capture in that position
<ro6>
yes, I'm updating my repro attempt to use a callback
<SeanTAllen>
can you open an issue for this saying here is the context, here is the error, if I change to X it works, sorry i havent been able to create a minimal example
<SeanTAllen>
its at least something that someone else might be able to create a minimal example from
<ro6>
sure, I'll spend a few minutes more on the reproduction to see if it has to do with the lambda and/or promise, but I'll post some issue regardless
<ro6>
SeanTAllen: yep, I think it's the lambda, I'll post an issue with my reproduction
<_etc>
SeanTAllen: Sorry I didn't respond yesterday - RC is awesome and it's cool to see its social rules here too!
jemc has joined #ponylang
jemc has quit [Client Quit]
jemc has joined #ponylang
aturley has quit [Ping timeout: 260 seconds]
plietar has quit [Remote host closed the connection]
plietar has joined #ponylang
bimawa has joined #ponylang
endformationage has joined #ponylang
plietar has quit [Ping timeout: 248 seconds]
aturley has joined #ponylang
<theodus_>
Is there any way to ensure that only one actor of a given type is can exist in pony (for FFI reasons)?
<jemc>
theodus_: probably not :/
<theodus_>
That's what I thought, but I figured i'd check
<jemc>
aturley: please consider adding the `pony-language` topic to your github repo, for better discoverability
<Praetonus>
theodus_: I think you can emulate a singleton by having private constructors on your actor and making a primitive `_init` in the same package that creates the actor and uses a shim C layer to store it in a global
<aturley>
jemc: will do
<Praetonus>
But that would be quite ugly
<theodus_>
Yeah, I've had to do that sort of stuff a couple of times.
Matthias247 has quit [Read error: Connection reset by peer]
<endformationage>
In the performance cheatsheet: "If it’s in hot path code, and you are talking about `error` happening in terms that are less than 1 in millions, you probably want the union type."
<endformationage>
Am I wrong to think this was meant to be the other way around? If so, it wasn't clear enough for me :\
<endformationage>
The section impressed on me that error is OK when it does not occur often. To me, 'less than 1 in millions' is very infrequent, and I though would be OK for `error`, but a `union` is suggested.
<SeanTAllen>
endformationage: that is incorrect
<SeanTAllen>
it should be
<endformationage>
If 1 in millions is too frequent for `error`, I think it should be made more clear.
<SeanTAllen>
hmmm wait
<SeanTAllen>
o no
<SeanTAllen>
that is correct
<SeanTAllen>
can you open a PR
<SeanTAllen>
if you are doing hot path code that is running a lot
<SeanTAllen>
and you have error happening every few million
<SeanTAllen>
you should switch to a union type
<SeanTAllen>
you want error to be very infrequent
<SeanTAllen>
in hot path, every few million can happen quite often
<endformationage>
^ OK, being new to 'performance' I am basically an order of mag off.
<endformationage>
Thanks for the clarification.
<endformationage>
Also thanks for the write up, I'm learning so much from Pony.
<endformationage>
.. and its community!
<endformationage>
Hmm, I think it was the "less than 1 in millions" part that threw me off. Perhaps could be changed to "at least once in millions" or something. It may just be my being new to the subject.
theodus_ has quit [Quit: theodus_]
ro6 has quit [Quit: Connection closed for inactivity]
jemc has quit [Read error: Connection reset by peer]
jemc has joined #ponylang
theodus_ has joined #ponylang
silverjam has joined #ponylang
_etc has joined #ponylang
<_etc>
I've got a C ffi call that is used in two places - one where I'm passing in an array of U32 and one where it's an array of F32 - is there any way to do this in pony?
<SeanTAllen>
the same method?
<_etc>
It's the same C function - it doesn't have to be called in the same pony method
<SeanTAllen>
what is the signature or the c function?
ro6 has quit [Quit: Connection closed for inactivity]
theodus_ has quit [Quit: theodus_]
_andre has quit [Quit: leaving]
<endformationage>
If I have a C return type of `OpaqueType**`, would the corresponding Pony FFI return type be `Pointer[Pointer[_OpaqueTypeHandle]]`? And would I be able to pass this to Array.from_cpointer?
<jemc>
endformationage: what does the C typedef for `OpaqueType` look like?
<jemc>
I'm inclined to say the corresponding Pony type should be `Pointer[_OpaqueTypeHandle]`, but I'm not sure without more context
<endformationage>
It's an opaque struct, as interface to a C++ object. The OpaqueType** is a returned array of these.
<Praetonus>
Note that `Array.from_cpointer` requires the pointer to be `pony_alloc`ed
<endformationage>
Hmm.
<Praetonus>
And regarding your original question, jemc is right. The correct Pony type is a one-level Pointer
<endformationage>
OK.
<jemc>
endformationage: what I was basically trying to ask about, is does the typedef look like this, or like something else? `typedef struct opaque_t opaque_t`
<Praetonus>
Pony types have a hidden level of indirection
<endformationage>
jemc: yeah
<jemc>
to give you good advice, it would be nice to know what the C semantics of this C call are
<jemc>
that is, why does the C call use `opaque_t**` instead of `opaque_t*`, and what are you supposed to do with the return value once you have it?
<jemc>
if it's a public C library I can probably look that up myself if you tell me which library/function
<endformationage>
One moment
<jemc>
usually when I see `opaque_t**` it's an argument type, not a return type
<Praetonus>
endformationage: I think I might be wrong on the Array.from_cpointer and non-pony_alloced memory
<Praetonus>
Let me check that
<endformationage>
OK, thanks
<Praetonus>
Yeah, I'm wrong. It's fine to do that
<endformationage>
Fwew!
<jemc>
Praetonus: why is it a restriction of `String.from_cpointer` and not so for `Array.cpointer` - what's the determining difference?
<endformationage>
.. I mean, I was probably going to try it anyway in my ignorance.
<Praetonus>
Hm, wait. There's something strange in the allocation algorithm
Matthias247 has quit [Read error: Connection reset by peer]
<Praetonus>
So `pony_realloc` has a case to handle reallocating non-pony memory, but that case has a bug
<Praetonus>
Since it can't know the size of the old memory area, it copies the old data based on the new size. Unless the new size is smaller, this will do an out of bounds read
<Praetonus>
I don't see any trickery that could allow us to retrieve the old size, so I think we'll have to remove that case
<jemc>
how can we ever realloc non-pony memory, if we don't know how that memory was allocated?
<Praetonus>
We can know that it was pony-allocated from the pagemap
<jemc>
I'm wondering - should we use a distinct `PointerUnmanaged` type for FFI cases where we cannot free or realloc the memory?
<jemc>
Praetonus: sure, we can detect the difference, but how can we meaningfully free something if we don't know what alloc function was used?
<Praetonus>
The PointerUnmanaged idea is interesting. I think it would be worth it to look at what APIs could look like with that
<Praetonus>
pony_realloc doesn't free anything (it leaves that to the GC) so that's not problematic. The issue is with the size of the memory area to copy
<Praetonus>
If the previous memory was pony-alloced, we get the size from the heap chunk, but if it wasn't, we have a problem
<jemc>
okay, so it's a separate problem
<jemc>
regarding freeing though - does Pony currently have any way of knowing the difference of whether it should free or not free the buffer when GC'ing a `Pointer`?
<Praetonus>
If it's in an Array or a String, it's treated as a field, so it'll be traced during GC and freed if it's unreachable
<Praetonus>
I'll look at what the compiler generates for a Pointer in a random object
<Praetonus>
jemc: It'll trace the Pointer itself, but not the underlying object(s)
<Praetonus>
So if you try to implement a custom Array containing Pony-alloced objects, the contained objects will be freed if they aren't referenced anywhere else, but the Pointer itself is fine
<Praetonus>
Though right now it's fine since you'd need public access to Pointer methods to do such a thing
<jemc>
related question, if I have a Pony struct or class that was not Pony-allocated, and it gets traced/collected by the GC, what happens? does the runtime try to free the pointer despite not being pony-allocated?
<Praetonus>
It will recurse on the fields of the object but it won't try to collect the object itself
<jemc>
cool
<jemc>
and the `_final` will be run, right?
<Praetonus>
Good question
<jemc>
(which presumably is implemented to call the C function that deallocates the object appropriately)
<Praetonus>
I don't think it will
<Praetonus>
You'll have to call _final manually when freeing the object
<Praetonus>
_final doesn't do any deallocation because other finalisers can still reference a finalised object
<jemc>
can you point me to the part(s) of the codebase where you've been looking these answers up?
<Praetonus>
It's mostly in libponyrt/mem/heap.c and libponyrt/gc/gc.c
<Praetonus>
And libponyc/codegen/gentrace.c for the Pointer tracing
silverjam has joined #ponylang
<jemc>
just to be clear, I'm talking about a case where `_final()` is implemented to call `@free_myclass(this)`
<jemc>
with not `Pointer`s involved
<Praetonus>
I don't think that'll work
<Praetonus>
Finalisers are called by the GC when parts of the heap are collected
<jemc>
where's the conditional that skips collection of an object that was not pony-allocated (and was obtained through C via something like `let myclass_instance = @create_myclass()`)
<Praetonus>
For example, in gc/gc.c:420 in ponyint_gc_sendobject, we try to get the heap chunk from the pagemap and if that fails, we don't update the GC bookkeeping
<Praetonus>
There's similar logic in the other ponyint_gc_* functions
<jemc>
so `ponyint_heap_owner` returns `NULL` in those cases?
<Praetonus>
No, it's ponyint_pagemap_get
<jemc>
ah, got it
<jemc>
heh, yeah there's a big ol' comment right in front of my face that says that
<jemc>
okay, so my practical takeaways from this part of the conversation:
<jemc>
- it's valid and okay to use an 'empty' Pony class as the type for a C-library-allocated opaque struct pointer
<jemc>
- but you can't use the finaliser of that class to free the object - you should call the C function to free it from the finaliser of another class that holds it as one of its fields
<Praetonus>
Yes
<jemc>
hm, actually may have to remove the "it's valid and okay" point above - because I just thought about runtime type matching
silverjam has quit [Ping timeout: 246 seconds]
<jemc>
if you tried to put such an object in a `match` block, all hell would break loose, since it has no Pony object header
<Praetonus>
Though if it's completely opaque, I'd recommend to use a `Pointer[None]`, it's less likely to mess up things accidentally
<Praetonus>
Particularly with regards to pattern matching, yes
<jemc>
okay
<jemc>
at some point I'd like to compose some FFI patterns / best practices to help organize my mental notes, make sure they make sense to you and others, and share them with newcomers
<Praetonus>
I think we'll need a full audit of the GC and the memory allocator, in order to precisely define the legal use of non-pony allocated memory in Pony code
<Praetonus>
I'll open an issue for that
<jemc>
yeah, we should have a clear set of rules for that
<jemc>
would also help to make sure somebody doing compiler refactors/optimizations is keeping those rules in mind
<jemc>
I've found proper memory management is usually the hairiest part when working as an FFI authors in a managed-memory language
<jemc>
but there's a hairy part with using those finalisers
<jemc>
for example, if you create an `Array[KoreGraphics4VertexElement]` from a `Pointer[Pointer[_KoreGraphics4VertexElementHandle] tag]`, and each of those "vertex elements" are actually supposed to still be owned by the "vertex structure", you *don't* want the deallocator to be called on it
<endformationage>
Wow, I just sent you all off on an hour tangent.
<endformationage>
right
<jemc>
so it seems that `KoreGraphics4VertexElement` needs to have some kind of `Bool` field tracking whether it is borrowed from some other structure, or if it is okay to be freed
<jemc>
and in your finaliser, respect the `Bool` and avoid calling `Kore_Graphics4_VertexElement_destroy` if it is borrowed
<jemc>
which is kind of hairy, but probably necessary if you need to deal with both created and borrowed objects