About me (visual)

React logo (visual)

const MyComponent = React.createClass({
  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
        <p>{this.props.summary}</p>
      </div>
    );
  }
});
function MyComponent(props) {
  return (
    <div>
      <h1>{props.title}</h1>
      <p>{props.summary}</p>
    </div>
  );
};
function MyComponent(props) {
  return (
    div({},
      h1({}, props.title),
      p({}, props.summary)
    )
  );
};
const description = (
  <MyComponent
    title="Hello"
    summary="World"
  />
);
const description = MyComponent({
  title: 'Hello',
  summary: 'World'
});
{
  type: 'div',
  props: {
    children: [{
      type: 'h1',
      props: {
        children: 'Hello'
      }
    }, {
      type: 'p',
      props: {
        children: 'World'
      }
    }]
  }
}
/**
 * runtime for DOM
 */
ReactDOM.render(description, mountNode);

/**
 * runtime for server/strings
 */
ReactServer.renderToString(description);
function testCase() {
  const description = MyComponent({
    title: 'Hello',
    summary: 'World'
  });

















}
function testCase() {
  const description = MyComponent({
    title: 'Hello',
    summary: 'World'
  });

  expect(description).toEqual({
    type: 'div',
    props: {
      children: [{
        type: 'h1',
        props: {
          children: 'Hello'
        }
      }, {
        type: 'p',
        props: {
          children: 'World'
        }
      }]
    }
  })
}
function testCase() {





















}
function testCase() {
  const description = (
    <MyComponent
      title="Hello"
      summary="World"
    />
  );







}
function testCase() {
  const description = (
    <MyComponent
      title="Hello"
      summary="World"
    />
  );

  expect(description).toEqual(
    <div>
      <h1>Hello</h1>
      <p>World</p>
    </div>
  );
}
function testCase() {













}
/**
 * Description
 */
const action = {
  type: 'INCREMENT'
};
/**
 * Decide how to handle
 * descriptions of actions
 */
function reducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    default:
      return state;
  }
}
/**
 * Creating a runtime
 */
const store = createStore(reducer);
/**
 * Creating a runtime
 */
const store = createStore(reducer);

/**
 * Passing a description
 * to the runtime to handle it
 */
store.dispatch(action);
function testCase() {
  










}
function testCase() {
  const initialState = 10;










}
function testCase() {
  const initialState = 10;

  const actions = [
    { type: 'INCREMENT' },
    { type: 'INCREMENT' },
    { type: 'INCREMENT' },
  ];




}
function testCase() {
  const initialState = 10;

  const actions = [
    { type: 'INCREMENT' },
    { type: 'INCREMENT' },
    { type: 'INCREMENT' },
  ];

  const nextState = actions.reduce(reducer, initialState);


}
function testCase() {
  const initialState = 10;

  const actions = [
    { type: 'INCREMENT' },
    { type: 'INCREMENT' },
    { type: 'INCREMENT' },
  ];

  const nextState = actions.reduce(reducer, initialState);

  expect(nextState).toEqual(13);
}
/**
 * Async action creator (thunk)
 */
function populateTodos() {
  return (dispatch) => {
    dispatch(populateTodosPending());

    return todoApi.getTodos()
    .then((todos) => dispatch(populateTodosSuccess({ todos })))
    .catch((error) => dispatch(populateTodosError({ error })));
  }
}
/**
 * Async action creator (thunk)
 */
function populateTodos() {
  return (dispatch) => {
    dispatch(populateTodosPending()); // side effect

    return todoApi.getTodos()
    .then((todos) => dispatch(populateTodosSuccess({ todos })))
    .catch((error) => dispatch(populateTodosError({ error })));
  }
}
/**
 * Async action creator (thunk)
 */
function populateTodos() {
  return (dispatch) => {
    dispatch(populateTodosPending()); // side effect

    return todoApi.getTodos() // side effect
    .then((todos) => dispatch(populateTodosSuccess({ todos })))
    .catch((error) => dispatch(populateTodosError({ error })));
  }
}
/**
 * A more general example
 */
function procedure() {
  const a = Math.random();
  console.log(a);

  if (a < 0.5) {
    console.log('low');
  } else {
    console.log('high');
  }

  return request(`/url/${a}`)
  .then((data) => writeToFile(`${a}.txt`, data))
  .catch((error) => console.log(error));
}
/**
 * A more general example
 */
function procedure() {
  const a = Math.random(); // side-effect
  console.log(a); // side-effect

  if (a < 0.5) {
    console.log('low'); // side-effect
  } else {
    console.log('high'); // side-effect
  }

  return request(`/url/${a}`) // side-effect
  .then((data) => writeToFile(`${a}.txt`, data)) // side-effect
  .catch((error) => console.log(error)); // side-effect
}
function procedure() {
  const a = Math.random();
  console.log(a);

  if (a < 0.5) {
    console.log('low');
  } else {
    console.log('high');
  }

  return request(`/url/${a}`)
  .then((data) => writeToFile(`${a}.txt`, data))
  .catch((error) => console.log(error));
}
function procedure() {
  const a = Math.random();
  console.log(a);

  if (a < 0.5) {
    console.log('low');
  } else {
    console.log('high');
  }

  return request(`/url/${a}`)
  .then((data) => writeToFile(`${a}.txt`, data))
  .catch((error) => console.log(error));
}


function testCase() {
  //....
}

Frank Procedure, Johnny Runtime & his evil twin brother

(a story)

function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

for (var num of countToThree()) {
  console.log(num);
}
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

const iterator = countToThree();
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

const iterator = countToThree();
iterator.next(); // { value: 1, done: false }
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

const iterator = countToThree();
iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: 2, done: false }
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

const iterator = countToThree();
iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: 2, done: false }
iterator.next(); // { value: 3, done: false }
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

const iterator = countToThree();
iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: 2, done: false }
iterator.next(); // { value: 3, done: false }
iterator.next(); // { value: 'finished', done: true }
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

for (var num of countToThree()) {
  console.log(num);
}

// 1
// 2
// 3
function* countToThree() {
  yield 1;
  yield 2;
  yield 3;
  return 'finished';
}

const iterator = countToThree();
iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: 2, done: false }
iterator.next(); // { value: 3, done: false }
iterator.next(); // { value: 'finished', done: true }

iterator.next(); // { value: undefined, done: true }
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
// -> logs out -> second number: 10
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
// -> logs out -> second number: 10
// jump to next yield
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
// -> logs out -> second number: 10
// jump to next yield
// { value: 3, done: false }
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
// -> logs out -> second number: 10
// jump to next yield
// { value: 3, done: false }
iter.next(15);
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
// -> logs out -> second number: 10
// jump to next yield
// { value: 3, done: false }
iter.next(15);
// -> logs out -> third number: 15
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
// -> logs out -> second number: 10
// jump to next yield
// { value: 3, done: false }
iter.next(15);
// -> logs out -> third number: 15
// jumps to return statement
function* countToThreeWhileLogging() {
  console.log('first number:', yield 1);
  console.log('second number:', yield 2);
  console.log('third number:', yield 3);
  return 'finished';
}

const iter = countToThreeWhileLogging();
iter.next();
// generator jumps to first yield
// { value: 1, done: false }
iter.next(5);
// -> logs out -> first number: 5
// jumps to next yield
// { value: 2, done: false }
iter.next(10);
// -> logs out -> second number: 10
// jump to next yield
// { value: 3, done: false }
iter.next(15);
// -> logs out -> third number: 15
// jumps to return statement
// { value: 'finished', done: true }
function* countToThreeWhileLogging() {
  console.log('first number:', 5);
  console.log('second number:', 10);
  console.log('third number:', 15);
  return 'finished';
}
/**
 * Creates descriptions
 */
function call(func, ...args) {
  return {
    type: '@@call',
    func,
    args
  };
}
/**
 * Example of creating an
 * effect description
 */
const description = call(console.log, 'hello', 'world');
{
  type: '@@call',
  func: console.log,
  args: ['hello', 'world']
}
/**
 * Performing descriptions of side effects
 */
function performEffect({ type, func, args }) {
  if (type === '@@call') {
    return Promise.resolve(func(...args));
  }
}
/**
 * Create an effect description as a value
 */
/**
 * Create an effect description as a value
 */
const description = call(console.log, 'hello', 'world');
/**
 * Create an effect description as a value
 */
const description = call(console.log, 'hello', 'world');

/**
 * Perform the effect described
 */
/**
 * Create an effect description as a value
 */
const description = call(console.log, 'hello', 'world');

/**
 * Perform the effect described
 */
performEffect(description);
/**
 * Create an effect description as a value
 */
const description = call(console.log, 'hello', 'world');

/**
 * Perform the effect described
 */
performEffect(description);
// -> hello world
performEffect({
  type: '@@call',
  func: console.log,
  args: ['hello', 'world']
});
performEffect({
  type: '@@call',
  func: console.log,
  args: ['hello', 'world']
});
// -> hello world
function runtime(generator) {
  const iterator = generator();
  const initialState = iterator.next();

  function recursivelyResolve(state) {
    return performEffect(state.value)
    .then((result) => iterator.next(result))
    .then((nextState) => {
      return nextState.done ?
      nextState.value :
      recursivelyResolve(nextState)
    });
  }

  return recursivelyResolve(initialState);
}
function procedure() {
  const a = Math.random();
  console.log(a);

  if (a < 0.5) {
    console.log('low');
  } else {
    console.log('high');
  }

  return request(`/url/${a}`)
  .then((data) => writeToFile(`${a}.txt`, data))
  .catch((error) => console.log(error));
}
function* procedure() {
  const a = yield call(Math.random);
  yield call(console.log, a);

  if (a < 0.5) {
    yield call(console.log, 'low');
  } else {
    yield call(console.log, 'high');
  }

  try {
    const data = yield call(request, `/url/${a}`);
    yield call(writeToFile, `${a}.txt`, data);
  } catch (error) {
    yield call(console.log, error);
  }
}
procedure();
runtime(procedure);
function testCase() {
function testCase() {
  const iterator = procedure();
function testCase() {
  const iterator = procedure();
  
  const step0 = iterator.next();
function testCase() {
  const iterator = procedure();
  
  const step0 = iterator.next();

  expect(step0.value).toEqual({
    type: '@@call',
    func: Math.random,
    args: []
  });
function testCase() {
  const iterator = procedure();
  
  const step0 = iterator.next();

  expect(step0.value).toEqual({
    type: '@@call',
    func: Math.random,
    args: []
  });

  const step1 = iterator.next(0.2);
function testCase() {
  const iterator = procedure();
  
  const step0 = iterator.next();

  expect(step0.value).toEqual({
    type: '@@call',
    func: Math.random,
    args: []
  });

  const step1 = iterator.next(0.2);

  expect(step1.value).toEqual({
    type: '@@call',
    func: console.log,
    args: [0.2]
  });
function testCase() {
  //...continues

function testCase() {
  //...continues

  const step2 = iterator.next();
function testCase() {
  //...continues

  const step2 = iterator.next();

  expect(step2.value).toEqual({
    type: '@@call',
    func: console.log,
    args: ['low']
  });
function testCase() {
  //...continues

  const step2 = iterator.next();

  expect(step2.value).toEqual({
    type: '@@call',
    func: console.log,
    args: ['low']
  });

  const step3 = iterator.next();
function testCase() {
  //...continues

  const step2 = iterator.next();

  expect(step2.value).toEqual({
    type: '@@call',
    func: console.log,
    args: ['low']
  });

  const step3 = iterator.next();

  expect(step3.value).toEqual({
    type: '@@call',
    func: request,
    args: [`/url/${0.2}`]
  });
function testCase() {
  //...continues

  const step2 = iterator.next();

  expect(step2.value).toEqual({
    type: '@@call',
    func: console.log,
    args: ['low']
  });

  const step3 = iterator.next();

  expect(step3.value).toEqual({
    type: '@@call',
    func: request,
    args: [`/url/${0.2}`]
  });

//...
function* slowPrint() {
  while (true) {
    const data = yield takeStream(process.stdin);
    const chars = data.toString().split('');

    let currentChar;
    while (currentChar = chars.shift()) {
      yield putStream(process.stdout, char);
      yield delay(50);
    }
  }
}

runtime(slowPrint);
{
  type: '@@takeStream',
  stream: process.stdin,
  args: []
}
{
  type: '@@takeStream',
  stream: process.stdin,
  args: []
}
{
  type: '@@putStream',
  stream: process.stdin,
  args: ['hello world']
}
{
  type: '@@takeStream',
  stream: process.stdin,
  args: []
}
{
  type: '@@putStream',
  stream: process.stdin,
  args: ['hello world']
}
{
  type: '@@delay',
  time: 50
}

Pushing it to the edge

By Eirik Langholm Vullum

Pushing it to the edge

A talk about side effects and JavaScript

  • 2,534