Cone Language Reference

with blocks: working on one value

On this page

You are working on one value part by part: read this field, change that one, call a method, add to a list. The value's name is written in front of every line, and it is noise. A with block focuses a block on one value, so its fields and methods are reached with a bare dot. This recipe has the form in full, including the one that changes the value through a reference, and the operators that act on the focused value. Structs introduced its short, read-only form, and Modularity has composition at every layer. Here a point is made one unit long:

mod with1;

import stdio use *;

struct Point {
  pub x f32;
  pub y f32;
}

fn main() {
  var point = new Point(3., 4.);

  // Make point one unit long: .x is point.x, through this
  with &mut point {
    let len = (.x * .x + .y * .y).sqrt();
    if len > 0. {
      .x /= len;
      .y /= len;
    }
  }
  print <- point.x, " ", point.y, "\n";
}

It prints:

0.6 0.8

Try this: take away the &mut, so the block is given point itself, and predict what happens. The compiler refuses both divisions: Error 1034: Cannot borrow a mutable reference to `this`, which is not mutable. Given a value rather than a reference, the block works on a copy of it, which may be read but not changed.

Focusing a block on one value#

A with block is an expression followed by a block. Its mechanism has two parts: a variable named this, defined for the block and holding the expression's value (not to be confused with a method's self), and operators that act on this when nothing is written to their left. It may look like method chaining, but it does more:

  • the methods called need not return their receiver, as chaining requires;
  • calls may come anywhere in the block's logic, between other statements, rather than strung together in one expression;
  • it reaches fields as well as methods.

The this variable#

Throughout the block, this holds the value of the expression after with:

// 'this' is the number of radians in a degree
with 3.14159f32 / 180. {
  quarter = 90. * this;    // 1.5708
  acute = 10. * this;      // 0.174533
}

is shorthand for

{
  let this = 3.14159f32 / 180.;
  quarter = 90. * this;
  acute = 10. * this;
}

with blocks may be nested, and then this in any statement is the innermost block's value.

The dot with nothing before it#

The dot operator normally has a value to its left, whose field it reaches or whose method it calls. With nothing to its left, it means this: .x is this.x. The program at the top of this page shows the usual pattern. Its block works on &mut point, a mutable reference, because it changes the point: without the reference, this would be a copy, which is let and is gone at the end of the block. Through the reference, .x and .y reach point's own fields, and the block reads more cleanly without point. in front of every one.

The send operator with nothing before it#

The send operator, <-, adds what is on its right to the collection on its left. With nothing on its left, it adds to this:

var numbers = new List[f32];
with &mut numbers {
  <- 3.4;
  <- 2.6;
  <- 1.4;
}
// numbers.len() is 3

To add several values with nothing else to do, the send operator alone is shorter: numbers <- 9.5, 8.5;.

.[]: indexing this (not built)#

Not built yet: the compiler refuses .[4].

.[] would reach an element of the collection this holds, as .[4] = 1.6; for numbers[4] = 1.6;.

You can now work on one value's parts without repeating its name, reading them from the value itself or changing them through a reference to it. The next recipe is for a match whose cases no literal, range or comparison can say: patterns of your own.