## Where communities thrive

• Join over 1.5M+ people
• Join over 100K+ communities
• Free without limits
##### Activity
• Oct 20 2019 22:59
@dockimbel banned @SmackMacDougal
• Dec 03 2017 05:53
@PeterWAWood banned @matrixbot
• Sep 28 2016 12:19
@PeterWAWood banned @TimeSeriesLord
• Aug 13 2016 03:23
@PeterWAWood banned @Vexercizer
@9214
@gltewalt have you read @githubnyn code?
Greg T
@gltewalt
I glanced at the above but I donâ€™t know what his goal is
@9214
@githubnyn
>> bar: [a [b 1]] baz: [a [b 2]]
== [a [b 2]]
>> rejoin ["ba" 'r]
== "bar"
== bar
== bar/a/b
== 1
== 2
Use copy where necessary.
Toomas Vooglaid
@toomasv
About insert and append - IIRC append is faster with longer blocks
hiiamboris
@hiiamboris

@9214 you're serious? you need proof that

x: append/dup [] 1 100 loop 100 [x: insert x 2] head x

is slower than

x: append/dup [] 1 100 insert x loop 100 [append [] 2] x

?

Toomas Vooglaid
@toomasv

@hiiamboris It makes sense to compare append and insert in as similar terms as possible. E.g. let's take two simple loops and ensure they are producing consistently the same result:

_insert: [x: append/dup copy [] 2 10 loop 10 [insert x 1] head x]
_append: [x: append/dup copy [] 1 10 loop 10 [append x 2] head x]
do _append
;== [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
do _append
;== [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
do _insert
;== [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
do _insert
;== [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]

Now, let's add volume to these and then profile:

>> _insert: [x: append/dup copy [] 2 10000 loop 10000 [insert x 1] head x]
>> _append: [x: append/dup copy [] 1 10000 loop 10000 [append x 2] head x]
>> profile/show [_append _insert]
Time         | Time (Per)   |      Memory | Code
0:00:00.004  | 0:00:00.004  |     2101248 | _append
0:00:00.208  | 0:00:00.208  |           0 | _insert
>> profile/show [_append _insert]
Count: 1
Time         | Time (Per)   |      Memory | Code
0:00:00.004  | 0:00:00.004  |     2101248 | _append
0:00:00.212  | 0:00:00.212  |           0 | _insert
>> profile/show [_append _insert]
Count: 1
Time         | Time (Per)   |      Memory | Code
0:00:00.005  | 0:00:00.005  |           0 | _append
0:00:00.207  | 0:00:00.207  |     2101248 | _insert

As you see append does much better on similar conditions.

hiiamboris
@hiiamboris
:+1: @toomasv that's exactly the point I'm advocating as well, also here red/red#2189
Suppose, collect/into - if based on insert - allows me to insert(keep) items into an arbitrary position in the series (versus append that is less flexible, always appends to the tail). But why would I want that? What need could possibly justify the overhead? This is beyond me..
hiiamboris
@hiiamboris

There's also a concern of in what sequence the results are inserted: in the code

>> x: [] collect/into [loop 5 [parse [3] [(keep 1 append x 2) collect into x keep skip]]] x
== [3 3 3 3 3 1 2 1 2 1 2 1 2 1 2]

the result will depend strongly on the implementation of each insertion operation.
I think append at the core of keep is easiest to reason about and implement, and keeps one safe from forgetting to provide series tail to collect/into. Isn't that the complexity reduction we're all striving for? ;)

BeardPower
@BeardPower
@hiiamboris Why you would want append? How about appending things!?
hiiamboris
@hiiamboris
:D don't append on me bro
@9214
@hiiamboris can you explain how this ever related to the crux of my request?
@9214
FYI, first snippet has minuscule advantage on time scale (also works much faster with x: removed which you may have intentionally placed there), and consumes less memory, which also adds to confusion of what your point is.
hiiamboris
@hiiamboris
@9214 my point was never about what index to return, but rather where to insert stuff. Maybe that confused you initially, but I believe you're able to see thru it without any additional remarks.
@9214
While keeping? I'd prefer insert, because it gives more tight control over inserting position, but I see that append is the most common need, and also doesn't have the overhead associated with moving portions of memory.
hiiamboris
@hiiamboris
Yes, that's it. Plus there arises a consistency problem with the keep from parse, which is trivially solved by append.
@dockimbel

@loziniak

It's sad because you sometimes have to work with callbacks, when you want to use C library that uses them.

R/S has no issue passing callbacks to imported functions from external C libraries. Such feature is used in many places in the Red's runtime library souce code.

Between R/S functions, passing a pointer! instead of a function!, then casting it to a function! works fine.

@9214 Please open a ticket for the missing object events firing (if that's the issue).
@9214
@dockimbel the issue is that object does not "re-own" a series to which one of its fields was set.
@dockimbel
Can you point me to an example?
@9214
Guh, Gitter search, not again...
Gimme a sec :wink:
@dockimbel
Ah wait, found it.
@9214
r: make object! [
a: [1 2 3]
b: [4 5 6]

on-deep-change*: func [owner word target action new index part][
print ['on-deep-change* tab word]
]

on-change*: func [word old new][
print ['on-change* tab word]
]
]

reverse/part r/a 2
r/a: [3 2 1]       ; <-- set field to a new series which object does not 're-owns'
reverse/part r/a 2 ; I expect this to fire on-deep-change*, but since new series is not owned by an object...
@dockimbel
Yes, an object will only own automatically the series used when creating it. After that, it's up to the user to manually attach/detach series from the object. If you don't want to do the work yourself, you can use reactor! or deep-reactor! instead, which provide general event handlers for that: https://github.com/red/red/blob/master/environment/reactivity.red#L30 (you can also extract the relevant lines from there and build your own event handler, and bypass the reactive stuff to improve performance).
@9214
@dockimbel so it's either insert clear r/a [3 2 1] or something else?
Like, I don't know, own new function inside -change* or something like that.
@dockimbel
@9214 I haven't followed the discussion, so don't know what you're asking for.
@9214
@dockimbel I've asked how to mark series as owned by an object manually, instead of relying on reactor! handlers, but you already pointed out the direction.
@dockimbel
modify action allows you to set or unset series flags.
@9214
Aha! I see now.
hiiamboris
@hiiamboris

omg.. I'm at a loss guys

collect1: :collect
collect2: func spec-of :collect body-of :collect
profile/count/show [
[collect1 [repeat i 10 [keep i]]]
[collect2 [repeat i 10 [keep i]]]
] 10000
Count: 10000
Time         | Time (Per)   | Memory      | Code
0:00:00.138  | 0:00:00      | 8978432     | [collect1 [repeat i n [keep i]]]
0:00:00.214  | 0:00:00      | 11243520    | [collect2 [repeat i n [keep i]]]

is magick at work here?

Toomas Vooglaid
@toomasv
@hiiamboris Interesting!
>> profile/count/show [[collect [repeat i 10 [keep i]]][collect1 [repeat i 10 [keep i]]][collect2 [repeat i 10 [keep i]]]] 10000
Count: 10000
Time         | Time (Per)   |      Memory | Code
0:00:00.123  | 0:00:00      |     8978432 | [collect [repeat i 10 [keep i]]]
0:00:00.131  | 0:00:00      |     8978432 | [collect1 [repeat i 10 [keep i]]]
0:00:00.184  | 0:00:00      |    11243520 | [collect2 [repeat i 10 [keep i]]]
>> profile/count/show [[collect [repeat i 10 [keep i]]][collect1 [repeat i 10 [keep i]]][collect2 [repeat i 10 [keep i]]]] 10000
Count: 10000
Time         | Time (Per)   |      Memory | Code
0:00:00.123  | 0:00:00      |     8978432 | [collect1 [repeat i 10 [keep i]]]
0:00:00.125  | 0:00:00      |     6877184 | [collect [repeat i 10 [keep i]]]
0:00:00.183  | 0:00:00      |    11243520 | [collect2 [repeat i 10 [keep i]]]
>> profile/count/show [[collect [repeat i 10 [keep i]]][collect1 [repeat i 10 [keep i]]][collect2 [repeat i 10 [keep i]]]] 10000
Count: 10000
Time         | Time (Per)   |      Memory | Code
0:00:00.122  | 0:00:00      |     6877184 | [collect1 [repeat i 10 [keep i]]]
0:00:00.123  | 0:00:00      |     8978432 | [collect [repeat i 10 [keep i]]]
0:00:00.195  | 0:00:00      |    11243520 | [collect2 [repeat i 10 [keep i]]]

@9214

Hmm... what message?

@toomasv @hiiamboris isn't collectand collect1 compiled hence faster?

hiiamboris
@hiiamboris
it's not a native!, how is it compiled?
moreover in all tests of compiled vs interpreted code I've tried - interpreted was faster by 20% or so ;)
Toomas Vooglaid
@toomasv
@nedzadarek I think @9214 referred to @dockimbel's message just before it
@hiiamboris I don't know the proper terms but here is an example (view uses layout):
layout: func spec-of :layout head insert (body-of :layout) [print "hello from new layout"]
view [base red]
view layout [base red]
; hello from new layout
@toomasv ah, I see, thank you
@dockimbel

@hiiamboris

it's not a native!, how is it compiled?

native! are written in R/S, function! are written in Red, and the ones provided by the runtime (the so-called "mezzanines") are compiled, hence the difference.

@hiiamboris

moreover in all tests of compiled vs interpreted code I've tried - interpreted was faster by 20% or so ;)

That would be odd, I suspect something is flawed with your measurement method. Remember that blocks of code run by do cannot be compiled (by design, as it's the way to invoke the interpreter).

@9214
@nedzadarek you were interested in how to roll out your own event handlers, @dockimbel pointed out the direction in his message.
hiiamboris
@hiiamboris

@dockimbel cool! I didn't know we can reflect the source of compiled funcs.
And you're right, I was using loop N [do code] since the compiler won't let me compile loop N code, so that explains it all, thanks!
Just checked:

x: 0
f: does [x: x + 1]
t: [now/precise/time/utc]
t1: do t
loop 1000000 [f]
t2: do t
print t2 - t1

is really about 2x faster when compiled

hiiamboris
@hiiamboris
Imbued collecta bit with more magic :) Faster, less allocation-prone. Makes sense only for compiled code though or for small collections (n < 10) https://gist.github.com/hiiamboris/a624c3d767dfe4e4ed20f23bc96433ff
@dockimbel
@hiiamboris Nice work! :+1:
hiiamboris
@hiiamboris
@dockimbel thanks :) the only drawback is that I can't meaningfully reflect it, not with the context parts...
@hiiamboris I'm confused about your usage of also. Why not just body': body coll': coll' shoot :keep coll?
How do you modify an owner the series/object? noneing old's owner works fine but when I try to modify new series I get access violation at the last line (reverse/part r/a 2):
r: make object! [
a: [1 2 3]
b: [4 5 6]

on-deep-change*: func [owner word target action new index part][
print ['on-deep-change* tab word]
]

on-change*: func [word old new][
print ['on-change* tab word]

if any [series? :old object? :old][modify old 'owned none]
if any [series? :new object? :new][modify new 'owned reduce [self word]]
]
]
]

reverse/part r/a 2
r/a: [3 2 1]       ; <-- set field to a new series which object does not 're-owns'
reverse/part r/a 2