Replies: 5 comments 1 reply
-
Some updates: I've now implemented this and have it working (including with various frameworks), other than for script optimization. Talking with @timwoj, he was persuasive that we should make the queues accessible from either end. Not hard, implementation-wise, given the internals are a C++ ... however this then brings up / deepens the question of syntax. We need effective ways to:
For a list Adding to the back of a queue is naturally expressed as Pop-from-front can be expressed as Talking with @ynadji, a different possibility is to leverage the existing
but this isn't so pretty, either, and would also involve changing an existing operator to have new positioning in the grammar. There may also be some lingering ambiguities when you have One other point: in experimenting with some scripting, it's already become apparent that sometimes it would be handy to iterate over two
though I think I'd only want that supported for Comments on these appreciated ... |
Beta Was this translation helpful? Give feedback.
-
This makes a lot of sense, and as a casual user of
Again as a casual user, these would have at first have unclear semantics to me (does Separately, I remember that we previously talked about potential confusing type behavior around I personally would prefer the following interface: # This provides functions not special statements.
# Add a single element (i.e., no `chain` semantics).
global push_front: function(xs: list of any, x: any);
global push_back: function(xs: list of any, x: any);
# Remove a single element.
global pop_front: function(xs: list of any, x: any);
global pop_back: function(xs: list of any, x: any); These should be pretty clear to most people familiar with basic data structures and easy to find (e.g., from grepping over shipped script code or searching the docs). The implementation of the bifs could invoke type conversions as needed (e.g., to append a
To me this looks like a very special flavor of Instead of expanding that special syntax to more types, a more general fix could be to add an local xs = vector(1, 2, 3); # Any container.
for ( i, x in xs ) {} # Currently supported.
for ( i, x in enumerate(xs) ) {} # Equivalent.
With that a zipped iteration could look like this for any random-access container (which local xs = vector("A", "B", "C");
local ys = vector("a", "b", "c");
# Not even binding value here for more uniform access in loop body.
for ( i, _ in enumerate(xs) )
{
print xs[i], ys[i];
}
I believe ideally adding language-level constructs should unlock more than a single use case, not only to be useful, but also since this makes it easier for users to develop familiarity with them elsewhere. Footnotes
|
Beta Was this translation helpful? Give feedback.
-
Looks like there are at least three topics: structuring access/push/pop for the new list type, "Zeekiness" in terms of syntactical solutions vs explicit functions, and how to potentially implement parallel iteration on multiple lists. I'll pick the middle one first. Zeek has long favored reliance on operators or keywords over explicit functions. This is controversial but I am rather partial to that, for a couple of reasons: once you're used to developing in that style, it feels quicker. Since Zeek doesn't use the "object-oriented" style of many other scripting languages ( Second, how to structure these operations for lists. Since we already have
These have some obvious pros/cons — the I tinkered with directional concatenation/separation operators since I initially liked the idea of starting from Third, parallel iteration. I'm partial here to the |
Beta Was this translation helpful? Give feedback.
-
Regarding syntax, I think using Here's my current thinking, where
For these last two, I find the |
Beta Was this translation helpful? Give feedback.
-
Regarding |
Beta Was this translation helpful? Give feedback.
-
A basic type Zeek lacks is a form of list or queue: an efficient way to maintain a sequence of elements optimized for adding at the end and removing from the beginning (or potentially vice versa). It's possible to create the equivalent using
table[count] of T
but that's much more heavyweight since it supports random access, and also clunkier because it has no innate notion of "beginning" or "end".My immediate use case is to allow efficient management of a large number of items that conceptually have individual, fixed-duration timers associated with them. Adding them to the end of a common queue and expiring the front when it's sufficiently old would provide a simple way of managing these.
For now I propose implementing a simple form of FIFO queue that allows appending to the back and removal from the front. Given that the keyword
list
is already reserved (andqueue
is not), that's the natural name to use. (Internally this would probably be calledTYPE_QUEUE
sinceTYPE_LIST
already has a separate internal meaning.)The usual
for
loop would iterate over the items, from front to back, and likewise the usual|x|
size operator would return the number of items in the list.delete l
for a listl
would clear it.There should be syntax for accessing the front and back elements, and for removing the front item and adding a new item to the back. For two of these there's fairly natural syntax -
l[0]
to access the front item of the listl
, andl += e
to add the elemente
to the back ofl
, ala' vectors.The other two aren't so obvious to me. One thought - not great - is
--l
for removing the front item inl
and returning its value. Logically,l[|l| - 1]
could refer to the last element ofl
, but that's clunky, and - more thanl[0]
, I think - suggests that random-access would work for lists, which I'm not thinking would be supported. I'm open to other thoughts for this. It'd be great to avoid BiFs, as currently they can only provide dynamic type-checking rather than static. We could add new keywords, as is done forcopy
, but that should go through a deprecation cycle, and it'd be unfortunate to delay this functionality for an entire major release. Maybe for now we just don't provide a way to access the last element (other than via iteration).For all of these, referring to items not in the list (such as accessing the front of an empty list) would generate run-time errors, in keeping with Zeek's style for other such operations. Down the line we could also consider adding various attributes to help with managing lists.
Beta Was this translation helpful? Give feedback.
All reactions