<veltas>
I think Forth's bad out-of-the-box reentrancy for normal programs is part of the extreme YAGNI you have to apply all the time, I think that something like what you suggest is probably possible using multiple tasks in polyforth though
<veltas>
I wouldn't know, I haven't tried using it
<veltas>
Of course yes you can use either dictionary space or something else to allocate effectively a stack of structured data you might need without keeping it all on the parameter/return stacks
<veltas>
The claim is that forth routines are "naturally reentrant" because they use the parameter/return stack only, and ones that use variables can be reentrant by replacing with user variables
<veltas>
4.6 explains how USER works
cantstanya has joined #forth
<cmtptr>
i agree with "yagni" but reentrancy is something that bites you when you least expect it, and it can be very difficult to debug
<cmtptr>
so i've adopted a very paranoid all-things-must-be-reentrant attitude
dave0 has quit [Read error: Connection reset by peer]
dave0 has joined #forth
marksmith has quit [Ping timeout: 265 seconds]
jsoft has joined #forth
<tabemann_>
at least in my forth, zeptoforth, each task gets its own dictionary space, so you can allocate stuff independent of all other tasks
<tabemann_>
(user variables are allocated from this dictionary space)
Gromboli has quit [Quit: Leaving]
boru` has joined #forth
boru has quit [Disconnected by services]
boru` is now known as boru
<cmtptr>
tabemann_, it's not just concurrency though. i guess my programming style makes heavy use of callbacks and function pointers, and you end up with reentrance sonetimes through circuitous recursion you didn't necessarily anticipate
<tabemann_>
that is the kind of thing that a heap is useful for
* tabemann_
wrote an optional heap for zeptoforth
<Zarutian_HTC>
I am wondering if that small object system I describred some days ago or variant thereof might help or not
<tabemann_>
objects are only really needed if there is inheritance
<tabemann_>
it just happens that so many languages suffer from the "if the only tool you have is a hammer" syndrome w.r.t. objects
<Zarutian_HTC>
I said object system NOT class system
<tabemann_>
what do you consider the difference to be?
* tabemann_
wrote an object/class system for an older forth of his, but as zeptoforth is for a small system, he did not consider the overhead to be worth it
<Zarutian_HTC>
a class system has all the issues of trying to stuff philosophical-trap categorytheory into something where it does not belong
<Zarutian_HTC>
in the system I described (used for gfx and gui) each object has an invocation handler field containing an xt to that handler
<cmtptr>
you're talking about oo as in smalltalk oo?
<tabemann_>
the object system I designed is IMHO interesting
<Zarutian_HTC>
naah more in the direction of Self but much more simplified
<tabemann_>
methods did not belong to classes
<tabemann_>
rather methods were like ordinary functions, with instances being defined for different classes independent of the method's original definition
<tabemann_>
so you could have class foobar and class foobaz, and you could define a method quux, after which you define implementations for classes foobar and foobaz
<tabemann_>
methods don't belong to any kind of class structure
<tabemann_>
e.g. you could make a method to-string, and then implement it for anything under the sun, without those classes having to inherit it
<Zarutian_HTC>
what I described is much simpler: : obj_invoke ( ... objptr methodSelector -- ... ) over obj_getHandlerXT execute ;
<tabemann_>
yeah, what I implemented was not simple at all; it used intmaps for mapping methods to classes, and these intmaps existed in the heap (yes, using the object system required configuring the heap)
<Zarutian_HTC>
the handler word can the do switch case or whatever dispatch it wants
<tabemann_>
from the user's perspective what I implemented, though, was quite nice - it was like CLOS methods minus multiple dispatch
<Zarutian_HTC>
I just needed something that could do gfx 2d scenegraph
<tabemann_>
yeah, what you implemented would work much better for small systems
<Zarutian_HTC>
made a variation on the dual space compacting garbage collector: the object memory is treated as circular buffer and each object has an colour bit. Each time gc is perforned the current colour is flipped. Any objects of the old colour are old and need to be copied over and then scanned
<tabemann_>
how do you follow pointers between objects?
<Zarutian_HTC>
oh and each object is composed of header, xt to handler, refs part, and data part (sizes of parts in the header)
<tabemann_>
ah
<Zarutian_HTC>
with obj_ref@ ( objptr refNrInObject -- reffered_objptr )
<tabemann_>
see, that seems overcomplicated for what I'm trying to do right now (e.g. the board I've got hooked up has 128K of usable (non-special) RAM)
<Zarutian_HTC>
seem over complicated but it really isnt
<tabemann_>
I'm not happy with the fact that my allocator needs 16 bytes (i.e. 4 cells) for the header of blocks allocated on the heap
<Zarutian_HTC>
why use a heap then? The circular object memory works for me
<Zarutian_HTC>
heck as I defined obj_@ obj_! obj_ptr+ the objects could be in an entirely diffrent memory device and not in pram/wram
<tabemann_>
how do you update references from the old heap to the new heap?
<tabemann_>
that's something I've never understood about copying GCs
<Zarutian_HTC>
during gc? I use obj_ref! and broken hearts which are put down one each per object moved at the objects old location
<Zarutian_HTC>
a broken heart is basically two cell structure, a header saying it is broken heart and not an object (one bit in the header) followed by a pointer to its new location
<tabemann_>
there's one big reason I wouldn't use this - zeptoforth is essentially supposed to be an RTOS, and GCs are not very realtime-friendly
<tabemann_>
for realtime code I wouldn't even use my heap
<tabemann_>
as allocation and freeing time are not predictable
<Zarutian_HTC>
yeah, I would not use it for even soft hard realtime applications
<Zarutian_HTC>
could use it in mixed criticality applications, one task-thread for the time critical stuff, another for the stuff using the objects and gc
<Zarutian_HTC>
of course using preemptive task switching using a timer interrupt or some such
<tabemann_>
another issue is that all tasks that use the GC heap would have to contend over a single lock to protect the heap
<Zarutian_HTC>
yebb
<tabemann_>
because a lock would be needed to protect the GC heap during GC, and to prevent GC from starting mid-usage
<Zarutian_HTC>
that is if they are using the same shared heap
<tabemann_>
well yes
<tabemann_>
for my heap I use critical sections, which in and of itself are not very realtime-friendly at all, but its allocation and freeing operations are much faster than a GC cycle
<tabemann_>
and allocation and freeing operations do not interfere with operations to access allocated blocks
<tabemann_>
so there is no need to have a critical section or lock/unlock when accessing already allocated blocks
<Zarutian_HTC>
hmm.. I have an suspiction I might be able to do conncurrent gc with the object system I described
<Zarutian_HTC>
or more accurately incremental gc
<tabemann_>
the problem is this
<tabemann_>
you've got a data block associated with each object
<tabemann_>
what if you get the pointer for a data block
<tabemann_>
and then GC starts
<tabemann_>
you write to the data block
<tabemann_>
but the GC has already moved the object
<tabemann_>
so your data is lost
<tabemann_>
so you'd need a dedicated copy in and copy out operation for objects
<Zarutian_HTC>
I see, the issue is the granularity of the operations here
<tabemann_>
to make data access Gc-safe
<tabemann_>
but at the same time this is all going to be expensive
<tabemann_>
essentially, you're going to need a lock to protect your GC heap, and you're going to need to take this lock every single time the GC heap is accessed in any way shape or form - or otherwise, you're going to have to guarantee that the GC heap is only ever accessed by a single task
<tabemann_>
a proper true lock may be too expensive for all this
<tabemann_>
so you might want a spinwait that PAUSEs each time it can't take a lock, and checks again when it regains control
<tabemann_>
it'll use more power, because you can't put the processor to sleep here
<Zarutian_HTC>
all field accesses are through obj_ref@ obj_ref! obj_datum@ obj_datum! and all do broken heart(s) chase. So the object only needs to be briefly locked while being moved or updated
<Zarutian_HTC>
why these word invoke broken heart(s) chase? it was cheap way to do something akin to Smalltalks become: operation
<tabemann_>
how do you handle the references to objects in the code being broken by copying GC, because unlike some languages you can't know what local variables (i.e. cells on the stack) hold pointers
<Zarutian_HTC>
hmm that one is trickier
<Zarutian_HTC>
yeah, I think incremental and or concurrent gc is out for now
<tabemann_>
I think you'd need something like a mini-heap consisting just of pointers to objects
<tabemann_>
it would be a mini-heap because it would consist solely of cells
<Zarutian_HTC>
in the gfx and gui stuff I am doing I plan to do gc at the end of every event loop turn (iteration) just to keep the amount of garbage down
<tabemann_>
the lowest bit would indicate whether the cells were free (a value of 1 would indicate free, a value of 0 would indicate used)
<tabemann_>
assuming that all allocated objects were cell-aligned
<tabemann_>
with this mini-heap you would gain a degree of indirection, allowing pointers to the actual objects which remain at the same place in memory
<Zarutian_HTC>
(I might not do gc every turn but x turns if I need to tune it)
<tabemann_>
you could also do it based on a percentage of memory used
<Zarutian_HTC>
eh, that I suspect could lead to extra embarrising gc pauses
<tabemann_>
tis true
<Zarutian_HTC>
I do not expect the number of objects to go above tens of thousands or so
<Zarutian_HTC>
hell, I might even be able to keep the objects in dram-ish memory device and have the gc copying act sort of memory refresh too
<Zarutian_HTC>
naah, simpler to use psuedo sram (dram with internal refresh circuitry)
* Zarutian_HTC
looks at clock and is off to bed
<Zarutian_HTC>
cya!
<tabemann_>
g'night
<MrMobius>
tabemann_, could you use something like a slab allocator?
<tabemann_>
slab allocators are pretty trivial, and don't really require much in the way of implementation
<tabemann_>
it's essentially a free ring with a very short critical section for when adding items to or removing items from the free ring
<tabemann_>
also, they are constant time
<MrMobius>
seems like the way to go for an RTOS
<tabemann_>
wait
<tabemann_>
from what I'm reading, slab allocation is more complex than that
<tabemann_>
because it assumes things like being able to allocate pages and whatnot
<tabemann_>
I'm thinking more memory pools
<MrMobius>
ya you cal make it more complex where you break down a big slab when you run out of small ones
<MrMobius>
you also need to know how many of each size youll need before hand which is hard and you end up wasting a lot of memory
<tabemann_>
I think I'm going to stick with memory pools
<tabemann_>
simple, fast, and constant-time
jsoft has quit [Ping timeout: 265 seconds]
Zarutian_HTC has quit [Remote host closed the connection]
hosewiejacke has joined #forth
sts-q has quit [Ping timeout: 260 seconds]
sts-q has joined #forth
gravicappa has joined #forth
hosewiejacke has quit [Ping timeout: 260 seconds]
jsoft has joined #forth
tangentstorm has quit [Ping timeout: 260 seconds]
tangentstorm has joined #forth
_whitelogger has joined #forth
hosewiejacke has joined #forth
xek has joined #forth
_whitelogger has joined #forth
hosewiejacke has quit [Ping timeout: 260 seconds]
hosewiejacke has joined #forth
hosewiejacke has quit [Remote host closed the connection]