event-based programming · things happen and when they happen, you want to know about it user...

31

Upload: others

Post on 03-Jun-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …
Page 2: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Event-based programmingDan S. Wallach and Mack Joyner, Rice University

Copyright © 2016 Dan Wallach, All Rights Reserved

Page 3: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Where’s the week10 code dump?

Should be online this afternoon If it makes you feel any better, your project this week is “from scratch”, so not much will be there beyond what you’ve already seen.

Page 4: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

What’s an event?

Page 5: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Things happenAnd when they happen, you want to know about it

User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Network programming Message arrival, connection success/failure, network status change, …

And more Clock “ticks”, battery/charging status, …

Common theme: when a thing happens, please call me!

Page 6: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Vocabulary

Callbacks, Observers, Listeners, EventHandlers, … Same basic idea: you register some code to run when something happens

Page 7: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

This stuff is used everywherejava.util Interface EventListener

All Known Subinterfaces: Action, ActionListener, AdjustmentListener, AncestorListener, AWTEventListener, BeanContextMembershipListener, BeanContextServiceRevokedListener, BeanContextServices, BeanContextServicesListener,CaretListener, CellEditorListener, ChangeListener, ComponentListener, ConnectionEventListener, ContainerListener, ControllerEventListener, DocumentListener, DragGestureListener, DragSourceListener,DragSourceMotionListener, DropTargetListener, FlavorListener, FocusListener, HandshakeCompletedListener, HierarchyBoundsListener, HierarchyListener, HyperlinkListener, IIOReadProgressListener,IIOReadUpdateListener, IIOReadWarningListener, IIOWriteProgressListener, IIOWriteWarningListener, InputMethodListener, InternalFrameListener, ItemListener, KeyListener, LineListener, ListDataListener,ListSelectionListener, MenuDragMouseListener, MenuKeyListener, MenuListener, MetaEventListener, MouseInputListener, MouseListener, MouseMotionListener, MouseWheelListener, NamespaceChangeListener,NamingListener, NodeChangeListener, NotificationListener, ObjectChangeListener, PopupMenuListener, PreferenceChangeListener, PropertyChangeListener, RowSetListener, RowSorterListener,SSLSessionBindingListener, StatementEventListener, TableColumnModelListener, TableModelListener, TextListener, TreeExpansionListener, TreeModelListener, TreeSelectionListener, TreeWillExpandListener,UndoableEditListener, UnsolicitedNotificationListener, VetoableChangeListener, WindowFocusListener, WindowListener, WindowStateListener All Known Implementing Classes: AbstractAction, AbstractButton.ButtonChangeListener, AWTEventListenerProxy, AWTEventMulticaster, BasicButtonListener, BasicColorChooserUI.PropertyHandler, BasicComboBoxEditor,BasicComboBoxEditor.UIResource, BasicComboBoxUI.FocusHandler, BasicComboBoxUI.ItemHandler, BasicComboBoxUI.KeyHandler, BasicComboBoxUI.ListDataHandler, BasicComboBoxUI.PropertyChangeHandler,BasicComboPopup.InvocationKeyHandler, BasicComboPopup.InvocationMouseHandler, BasicComboPopup.InvocationMouseMotionHandler, BasicComboPopup.ItemHandler, BasicComboPopup.ListDataHandler,BasicComboPopup.ListMouseHandler, BasicComboPopup.ListMouseMotionHandler, BasicComboPopup.ListSelectionHandler, BasicComboPopup.PropertyChangeHandler, BasicDesktopIconUI.MouseInputHandler,BasicDesktopPaneUI.CloseAction, BasicDesktopPaneUI.MaximizeAction, BasicDesktopPaneUI.MinimizeAction, BasicDesktopPaneUI.NavigateAction, BasicDesktopPaneUI.OpenAction, BasicDirectoryModel,BasicFileChooserUI.ApproveSelectionAction, BasicFileChooserUI.CancelSelectionAction, BasicFileChooserUI.ChangeToParentDirectoryAction, BasicFileChooserUI.DoubleClickListener,BasicFileChooserUI.GoHomeAction, BasicFileChooserUI.NewFolderAction, BasicFileChooserUI.SelectionListener, BasicFileChooserUI.UpdateAction, BasicInternalFrameTitlePane.CloseAction,BasicInternalFrameTitlePane.IconifyAction, BasicInternalFrameTitlePane.MaximizeAction, BasicInternalFrameTitlePane.MoveAction, BasicInternalFrameTitlePane.PropertyChangeHandler,BasicInternalFrameTitlePane.RestoreAction, BasicInternalFrameTitlePane.SizeAction, BasicInternalFrameUI.BasicInternalFrameListener, BasicInternalFrameUI.BorderListener,BasicInternalFrameUI.ComponentHandler, BasicInternalFrameUI.GlassPaneDispatcher, BasicInternalFrameUI.InternalFramePropertyChangeListener, BasicLabelUI, BasicListUI.FocusHandler,BasicListUI.ListDataHandler, BasicListUI.ListSelectionHandler, BasicListUI.MouseInputHandler, BasicListUI.PropertyChangeHandler, BasicMenuItemUI.MouseInputHandler, BasicMenuUI.ChangeHandler,BasicMenuUI.MouseInputHandler, BasicOptionPaneUI.ButtonActionListener, BasicOptionPaneUI.PropertyChangeHandler, BasicProgressBarUI.ChangeHandler, BasicRootPaneUI,BasicScrollBarUI.ArrowButtonListener, BasicScrollBarUI.ModelListener, BasicScrollBarUI.PropertyChangeHandler, BasicScrollBarUI.ScrollListener, BasicScrollBarUI.TrackListener,BasicScrollPaneUI.HSBChangeListener, BasicScrollPaneUI.MouseWheelHandler, BasicScrollPaneUI.PropertyChangeHandler, BasicScrollPaneUI.ViewportChangeHandler, BasicScrollPaneUI.VSBChangeListener,BasicSliderUI.ActionScroller, BasicSliderUI.ChangeHandler, BasicSliderUI.ComponentHandler, BasicSliderUI.FocusHandler,

Page 8: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Typical use (Android)“Find” your UI widgets, register listeners on them liteButton = (RadioButton) findViewById(R.id.liteButton); toolButton = (RadioButton) findViewById(R.id.toolButton); numbersButton = (RadioButton) findViewById(R.id.numbersButton);clockView = (MyViewAnim) findViewById(R.id.surfaceView); secondsSwitch = (Switch) findViewById(R.id.showSeconds); dayDateSwitch = (Switch) findViewById(R.id.showDayDate); View.OnClickListener myListener = new View.OnClickListener() { public void onClick(View v) { // fetch state from UI widgets, redraw screen }}; liteButton.setOnClickListener(myListener);toolButton.setOnClickListener(myListener);numbersButton.setOnClickListener(myListener);secondsSwitch.setOnClickListener(myListener);dayDateSwitch.setOnClickListener(myListener);

Page 9: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Find the widget, set its listener.

Typical use (Android)“Find” your UI widgets, register listeners on them liteButton = (RadioButton) findViewById(R.id.liteButton); toolButton = (RadioButton) findViewById(R.id.toolButton); numbersButton = (RadioButton) findViewById(R.id.numbersButton);clockView = (MyViewAnim) findViewById(R.id.surfaceView); secondsSwitch = (Switch) findViewById(R.id.showSeconds); dayDateSwitch = (Switch) findViewById(R.id.showDayDate); View.OnClickListener myListener = new View.OnClickListener() { public void onClick(View v) { // fetch state from UI widgets, redraw screen }}; liteButton.setOnClickListener(myListener);toolButton.setOnClickListener(myListener);numbersButton.setOnClickListener(myListener);secondsSwitch.setOnClickListener(myListener);dayDateSwitch.setOnClickListener(myListener);

Page 10: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Shared “listener” (anon. inner class, Java7’s almost-lambda)

Typical use (Android)“Find” your UI widgets, register listeners on them liteButton = (RadioButton) findViewById(R.id.liteButton); toolButton = (RadioButton) findViewById(R.id.toolButton); numbersButton = (RadioButton) findViewById(R.id.numbersButton);clockView = (MyViewAnim) findViewById(R.id.surfaceView); secondsSwitch = (Switch) findViewById(R.id.showSeconds); dayDateSwitch = (Switch) findViewById(R.id.showDayDate); View.OnClickListener myListener = new View.OnClickListener() { public void onClick(View v) { // fetch state from UI widgets, redraw screen }}; liteButton.setOnClickListener(myListener);toolButton.setOnClickListener(myListener);numbersButton.setOnClickListener(myListener);secondsSwitch.setOnClickListener(myListener);dayDateSwitch.setOnClickListener(myListener);

Page 11: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Closer to home: SparkJava web server

When we see the URL “/hello” or “/hello2”, run the given lambda: public class SimpleServer { public static void main(String[] args) { get("/hello", (request, response) -> "Hello, world"); get("/hello2", (request, response) -> html().with( head().with(title("Hello, world")), body().with( h1("Hello, world"), p("This is some introductory test"))));

Page 12: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Event handler for the “/hello” URL

Closer to home: SparkJava web server

When we see the URL “/hello” or “/hello2”, run the given lambda: public class SimpleServer { public static void main(String[] args) { get("/hello", (request, response) -> "Hello, world"); get("/hello2", (request, response) -> html().with( head().with(title("Hello, world")), body().with( h1("Hello, world"), p("This is some introductory test"))));

Page 13: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

In a world with mutation…

Events are used to respond to changes in state

Scoreboard on top Listen to changes in player “health” Listen to click, display remaining time

Players Listen to status of other players (e.g., “if suffering damage, laugh!”)

Page 14: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Why listeners and mutation are awfulDependencies kill you A listens to B, B listens to C, C listens to A? Circular dependencies can lead to infinite recursion! Engineering challenge: maintaining discipline in event dispatches

• What you really want: a “directed acyclic graph” • But there’s no code tool to help you enforce it!

It’s also confusing to debug An event can lead to a cascade of listeners being called Hard to determine causality: why did some callbacks happen?

Page 15: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

What about a functional world?There are several general-purpose “functional-reactive programming” (FRP) frameworks like RxJava Here’s an introduction: https://www.bignerdranch.com/blog/what-is-functional-reactive-programming/

We’re not going to go there in Comp215 These frameworks deal with concurrency / multithreading (That’s Comp322 and maybe Comp311)

If you do see FRP code, it looks just like lazy list code Filters, maps, etc. on events that haven’t happened yet. “Subscribe” to events and emit more events. Your Comp215 experience means you’re ready to understand FRP.

Page 16: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

How do text adventures work?First, let’s go and play a classic: Zork http://iplayif.com/?story=http%3A%2F%2Fwww.ifarchive.org%2Fif-archive%2Fgames%2Fzcode%2Fzdungeon.z5

Page 17: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

What about your adventure game?Example: How might you deal with locked doors?

Keys are functions that update doors from “locked” to “unlocked” The key (or door) might verify that they match properly

Door opening? Another function. Check if the door is unlocked, etc.

Navigating through a door? Another function. Check if there’s a door; if so, run its function. Compose with the function to traverse any exit.

Page 18: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Use monadic composition!

flatmap matchmap

Inputs: Option<state of the world>, desired action

Outputs: Option<state of the world>

Page 19: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

More adventure game fun

How might you deal with the pansy of perplexity?

Time-based effects World-state: tracks when the effect starts and ends, updates an “active” or “inactive” field. The “pansy” function is the identity function unless “activated”.

Command-based effects The “pansy” transforms motion comments to different motion commands, or it’s the identity function.

Many different ways to accomplish the same goal!

Page 20: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

How do you connect typed commands?> HIT TROLL WITH SWORD

> HIT TROLL WITH FLOWER One of these will be more effective than the other! Special attributes on weapons that normal objects don’t have?

> HIT <target> WITH <item> You need a general-purpose way to map from names to items And then you need a way to read each object’s properties The “hit” verb will query the environment for your <target> and query your inventory for the <item>

Page 21: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Expect to build a bunch of “registries”private static final IMap<RPNTokenPatterns, CalcOp> REGISTRY = TreapMap.of( KeyValue.make(RPNTokenPatterns.PLUS, RPNCalculator::add), KeyValue.make(RPNTokenPatterns.TIMES, RPNCalculator::multiply), KeyValue.make(RPNTokenPatterns.MINUS, RPNCalculator::subtract), KeyValue.make(RPNTokenPatterns.DIVIDE, RPNCalculator::divide), KeyValue.make(RPNTokenPatterns.DUP, RPNCalculator::dup), KeyValue.make(RPNTokenPatterns.DROP, RPNCalculator::drop), KeyValue.make(RPNTokenPatterns.SWAP, RPNCalculator::swap), KeyValue.make(RPNTokenPatterns.EQUALS, RPNCalculator::noop), KeyValue.make(RPNTokenPatterns.FAIL, RPNCalculator::fail), KeyValue.make(RPNTokenPatterns.CLEAR, RPNCalculator::clear));

Or, perhaps, use the JSON functions directly. You can make a choice for how to do this!

Page 22: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

You can update a registry as wellprivate static final IMap<RPNTokenPatterns, CalcOp> REGISTRY = TreapMap.of( KeyValue.make(RPNTokenPatterns.PLUS, RPNCalculator::add), KeyValue.make(RPNTokenPatterns.TIMES, RPNCalculator::multiply), KeyValue.make(RPNTokenPatterns.MINUS, RPNCalculator::subtract), KeyValue.make(RPNTokenPatterns.DIVIDE, RPNCalculator::divide), KeyValue.make(RPNTokenPatterns.DUP, RPNCalculator::dup), KeyValue.make(RPNTokenPatterns.DROP, RPNCalculator::drop), KeyValue.make(RPNTokenPatterns.SWAP, RPNCalculator::swap), KeyValue.make(RPNTokenPatterns.EQUALS, RPNCalculator::noop), KeyValue.make(RPNTokenPatterns.FAIL, RPNCalculator::fail), KeyValue.make(RPNTokenPatterns.CLEAR, RPNCalculator::clear));

update() method on a registry, leaves the original alone Perhaps wrap existing functions, perhaps replace them (temporarily?)

Page 23: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Function composition!

flatmap matchmap

This is a universal technique: support non-player characters (e.g., the troll or the thief) area effects (e.g., illumination)

Each transforms the world, returns another world But test them individually!

Page 24: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

How should output text work?

How about a field in your world that represents the text output? As each transformer operates, it might append some text. At the end of the turn, you collect all the text and print it.

If one of the world functions has an error? Throw away the output buffer, return a world in the “error” state. Errors should include text about what went wrong

• Not just Option.none ? Don’t advance the state of the world when there’s an error?

Page 25: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

How should you begin?This week’s deadline is pretty mellow Load your world (in JSON format) Walk around Look at the rooms

Architect how your world works! What’s your in-memory representation? What’s it mean to move? What’s it mean to look? What’s a room? What’s a door?

Page 26: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Maybe convert JSON to native classes

We talked about this in week7 (edu.rice.week7newspaper):

public interface DB { class Author { public final String email; public final String name; private Author(String email, String name) { this.email = email; this.name = name; }

It’s probably worth it to go with a “native” database for your world.

Page 27: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Another hint: dealing with text input

Don’t bother with scanning and parsing You’re dealing with a very simple command language <Command> ::= <Verb> | <Verb> <Object> | <Verb> …

1) split the input string on whitespace

2) map from <Verb> to a lambda

3) call that lambda with the world and the rest of the input string!

Page 28: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Testing, testing, testing!

Create very simple worlds for your tests One room, one object in the room, etc.

Create very simple functions that operate on those rooms Pick up an object, drop an object, etc.

Unit test them individually

Don’t compose them until they work on their own

Page 29: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

But… but… performance!

How many objects and rooms in your world? Hundreds? If each one executes for a million CPU cycles (assuming 1GHz CPU):

• that’s 1 ms / object • Or 100 ms / user command

So your performance basically doesn’t matter! The final project will be another matter entirely

Page 30: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

When does performance matter?1) If you’re trying to draw the screen at 60+Hz “Jank is any stuttering, juddering or just plain halting that users see when a site or app isn't keeping up with the refresh rate. Jank is the result of frames taking too long … to make, and it negatively impacts your users and how they experience your site or app.” (more on this coming soon)

2) If you’re running a huge computation Think: Google-scale, where your electricity bills are $millions/year.

3) If you’re running on a tiny computer Think: A pacemaker, where you need surgery to replace a battery.

Page 31: Event-based programming · Things happen And when they happen, you want to know about it User interface programming Button clicks, mouse motion, keyboard input, window resize, …

Q&A

In-class discussion.