# Pattern matching for the Bro language

**URL:** <https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774>\
**Category:** Development\
**Tags:** development\
**Created:** [August 19, 2015, 3:43pm UTC](https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774 "2015-08-19T15:43:11Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Matthias\_Vallentin1](https://yyz1.discourse-cdn.com/flex011/user_avatar/community.zeek.org/matthias_vallentin1/32/596_2.png) [@Matthias\_Vallentin1](https://community.zeek.org/u/Matthias_Vallentin1)\
**Post date:** [August 19, 2015, 3:43pm UTC](https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774/1 "2015-08-19T15:43:11Z")

</div>

TL;DR:

&nbsp;&nbsp;&nbsp;&nbsp;function f() : any;

&nbsp;&nbsp;&nbsp;&nbsp;local result = "";  
&nbsp;&nbsp;&nbsp;&nbsp;switch( f() )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case addr:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( x in 10.0.0.0/8 )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = "got it!";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case string:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = "f() failed: " + x;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

I want to propose introducing pattern matching for the Bro language.  
Pattern matching is a powerful concept particularly available in  
functional languages, like Haskell, ML, Erlang, Rust, you name it. It  
enables typesafe dispatching based on the type of a value. Other  
languages often can go beyond type-based dispatching and also enable  
"value" dispatch. We \*kinda\* have this with the when statement in an  
asynchronous form, which monitors a given expression value, and whenever  
the operands change, the expression is re-evaluated.

But, let's get back to type-based dispatch and "any". The "any" type is  
really just a bolt-on fix for the lack of a more sophisticated type  
system. We use (and abuse) it anywhere where we need polymorphism and  
want to bypass the type system. Today, Bro doesn't have generic  
programming facilities besides "any". I hope this will change in the  
future; introducing pattern matching is the first step in this  
direction.

In the future, I believe that in Bro we see more and more asynchronous  
operations, in particular with the proliferation of Broker. This  
requires better language support. When users store data remotely and  
need to wait for answer. The asynchrony often introduces sum types:  
either the result comes back or an error occurs. The above example is  
such a sum type: either an addr or a string. If "x" has neither type,  
Bro would raise an error---at runtime. Here's a another example:

&nbsp;&nbsp;&nbsp;&nbsp;function lookup(key: string) : any;

&nbsp;&nbsp;&nbsp;&nbsp;when ( local x = lookup("key") )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local result = "";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch( x )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case addr:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( x in 10.0.0.0/8 )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = "contained";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case string:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = "error: lookup() failed: " + x;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

When we ask a store for data, the runtime doesn't know the type until it  
gets a result back. Because there can be multiple return types, "switch"  
provides a means to extract the value in a type-safe manner.

Some languages (Ruby comes to mind) design switch as an expression,  
which would allow constructs like:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local result = switch( x )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case T:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case U:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};

Personally, I like this functional treatment, but C-seasoned folks may  
have a harder time with it.

If you have any thoughts on this, please chime in.

&nbsp;&nbsp;&nbsp;&nbsp;Matthias

---

<div class="post-metadata">

**Author:** ![Vern](https://yyz1.discourse-cdn.com/flex011/user_avatar/community.zeek.org/vern/32/630_2.png) [@Vern](https://community.zeek.org/u/Vern)\
**Post date:** [August 19, 2015, 7:09pm UTC](https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774/2 "2015-08-19T19:09:01Z")

</div>

> I want to propose introducing pattern matching for the Bro language.

Per our discussion yesterday, I like this notion in general. (Seems we  
need a better term for it, though, as "pattern matching" is very generic -  
plus will confuse some people who'll think it refers to NIDS rules rather  
than generic type safety!)

> Some languages (Ruby comes to mind) design switch as an expression,  
> which would allow constructs like:
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local result = switch( x )  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case T:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case U:  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};

Personally, this strike me as a tad weird, since now "result" might not  
have a statically determined type, so we're back to it being "any".  
So I'd want to wait on going this far until we have use cases where  
it clearly would help with code clarity.

&nbsp;&nbsp;&nbsp;&nbsp;Vern

---

<div class="post-metadata">

**Author:** ![Matthias\_Vallentin1](https://yyz1.discourse-cdn.com/flex011/user_avatar/community.zeek.org/matthias_vallentin1/32/596_2.png) [@Matthias\_Vallentin1](https://community.zeek.org/u/Matthias_Vallentin1)\
**Post date:** [August 19, 2015, 8:15pm UTC](https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774/3 "2015-08-19T20:15:56Z")

</div>

> \> local result = switch( x )  
> \> {  
> \> case T:  
> \> case U:  
> \> };
> 
> Personally, this strike me as a tad weird, since now "result" might not  
> have a statically determined type, so we're back to it being "any".

To avoid falling back to "any land," the additional constraint in this  
case would be that each case block would have to have a return statement  
with the same type.

The use case I had in mind is returning from a function.

&nbsp;&nbsp;&nbsp;&nbsp;function f(x: any) : string  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return switch(x)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case T:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return "T";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case U:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return "U";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

Though that's simply syntactic sugar for:

&nbsp;&nbsp;&nbsp;&nbsp;function f(x: any) : string  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local result = "";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(x)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case T:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = "T";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case U:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = "U";  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

I'm not feeling very strong about it.

&nbsp;&nbsp;&nbsp;&nbsp;Matthias

---

<div class="post-metadata">

**Author:** ![robin](https://yyz1.discourse-cdn.com/flex011/user_avatar/community.zeek.org/robin/32/599_2.png) [@robin](https://community.zeek.org/u/robin)\
**Post date:** [August 20, 2015, 3:15pm UTC](https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774/4 "2015-08-20T15:15:31Z")

</div>

Had discussed this with Matthias before, but for the record: I like  
it, too. 🙂 (This form; less the one with return values, at least for  
now).

As one additional note, even with this added, we wouldn't otherwise  
extend the operations that are allowed on "any" instances. Right now,  
there's actually not much one can do with them, and it would stay that  
way to avoid people starting to generally skip the typing system  
(e.g., one cannot assign an "any" to another "any"; more generally,  
one cannot pass them around arbitrarily). The "switch" is for using  
"any" safely in cases where it cannot be avoided (which is primarily  
bifs with return values that cannot be statically typed).

Robin

---

<div class="post-metadata">

**Author:** ![Seth\_Hall3](https://avatars.discourse-cdn.com/v4/letter/s/d6d6ee/32.png) [@Seth\_Hall3](https://community.zeek.org/u/Seth_Hall3)\
**Post date:** [August 20, 2015, 4:41pm UTC](https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774/5 "2015-08-20T16:41:53Z")

</div>

I like this proposal a lot too.

&nbsp;&nbsp;.Seth

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex011/uploads/zeek/original/1X/f09d732bc2cc7c7cc7e35db67cf4e1d5233ce7a7.png) [@system](https://community.zeek.org/u/system)\
**Post date:** [May 6, 2022, 3:42pm UTC](https://community.zeek.org/t/pattern-matching-for-the-bro-language/3774/6 "2022-05-06T15:42:59Z")

</div>


