英文:
How do I register different events in a supply in Raku?
问题
"Hopefully 'events' isn't a misnomer in Rakuland. As far as I understand, Supplies are the Raku equivalent for 'events' in other programming languages such as NodeJS. In NodeJS, you can register different events which can be targeted specifically with emit
's first parameter. Is it possible to do this in Raku?"
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
eventEmitter.on('start', () => {
console.log('started');
});
eventEmitter.on('end', (value) => {
console.log(`ended ${value}`);
});
eventEmitter.emit('start');
eventEmitter.emit('end', 23);
"I'm reading 'A nice supplies: syntactic relief for working with asynchronous data' (which I haven't finished yet) and I see jnthn implements a subscription mechanism with 'subscribe' and 'send' so I'm wondering if that's the way to go about it."
英文:
Hopefully "events" isn't a misnomer in Rakuland. As far as I understand, Supplies are the Raku equivalent for "events" in other programming languages such as NodeJS. In NodeJS, you can register different events which can be targeted specifically with emit
's first parameter. Is it possible to do this in Raku?
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
eventEmitter.on('start', () => {
console.log('started');
});
eventEmitter.on('end', (value) => {
console.log(`ended ${value}` );
});
eventEmitter.emit('start');
eventEmitter.emit('end', 23);
I'm reading A nice supplies: syntactic relief for working with asynchronous data (which I haven't finished yet) and I see jnthn implements a subscription mechanism with subscribe
and send
so I'm wondering if that's the way to go about it.
答案1
得分: 17
A Supply
is a suitable mechanism for event distribution, but unlike EventEmitter
, it doesn't directly have a named events mechanism - in part because Raku already has plentiful ways to filter and dispatch, which can be reused for the purpose.
The most common approach is to use typed messages:
class Start { }
class End {
has $.value
}
Given a Supplier
, we can emit these:
my $supplier = Supplier.new;
$supplier.emit(Start); # Don't need an instance if there's no data
$supplier.emit(End.new(value => 42));
The receiving end is the Supply
:
my $supply = $supplier.Supply;
Typically, the thing doing the emitting keeps the Supplier
private and returns the Supply
, which only allows receiving.
On the receiving end, we have a multitude of ways to work with the events. For example, we could translate your example most directly as:
$supply.grep(Start).tap: {
say "started";
}
$supply.grep(End).tap: {
say "ended {.value}";
}
If using a structured supply
or react
block that'd be:
react {
whenever $supply.grep(Start) {
say "started";
}
whenever $supply.grep(End) {
say "ended {.value}";
}
}
Or one might prefer to use the when
match construct:
$supply.tap: {
when Start { say "started"; }
when End { say "ended {.value}"; }
}
Which again works similarly in the structured approach:
react {
whenever $supply {
when Start { say "started"; }
when End { say "ended {.value}"; }
}
}
Or one could write multiple dispatch routines and subscribe to those:
multi process(Start) {
say "started";
}
multi process(End (:$value)) { # Can destructure the message in the signature
say "ended $value";
}
$supply.tap(&process);
Besides the flexibility of approach on the receiving end, another advantage is that typos in class names will be detected at compile time, whereas typos in strings - at least if you're not in TypeScript or something similar - are likely to end up being noticed until rather later.
英文:
A Supply
is a suitable mechanism for event distribution, but unlike EventEmitter
it doesn't directly have a named events mechanism - in part because Raku already has plentiful ways to filter and dispatch, which can be reused for the purpose.
The most common approach is to use typed messages:
class Start { }
class End {
has $.value
}
Given a Supplier
we can emit these:
my $supplier = Supplier.new;
$supplier.emit(Start); # Don't need an instance if there's no data
$supplier.emit(End.new(value => 42));
The receiving end is the Supply
:
my $supply = $supplier.Supply;
Typically, the thing doing the emitting keeps the Supplier
private and returns the Supply
, which only allows receiving.
On the receiving end, we have a multitude of ways to work with the events. For example, we could translate your example most directly as:
$supply.grep(Start).tap: {
say "started";
}
$supply.grep(End).tap: {
say "ended {.value}";
}
If using a structured supply
or react
block that'd be:
react {
whenever $supply.grep(Start) {
say "started";
}
whenever $supply.grep(End) {
say "ended {.value}";
}
}
Or one might prefer to use the when
match construct:
$supply.tap: {
when Start { say "started"; }
when End { say "ended {.value}"; }
}
Which again works similarly in the structured approach:
react {
whenever $supply {
when Start { say "started"; }
when End { say "ended {.value}"; }
}
}
Or one could write multiple dispatch routines and subscribe those:
multi process(Start) {
say "started"
}
multi process(End (:$value)) { # Can destructure the message in the signature
say "ended $value"
}
$supply.tap(&process);
Besides the flexibility of approach on the receiving end, another advantage is that typos in class names will be detected at compile time, whereas typos in strings - at least if you're not in TypeScript or something similar - are likely to end up being noticed until rather later.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论