Skip to content

Commit

Permalink
Remove error handling from expression evaluation exercise (#2517)
Browse files Browse the repository at this point in the history
I think it would be good to simplify the expression evaluation exercise
by removing the error handling around the divide-by-zero case. I think
it overcomplicates the exercise and and adds confusion since at this
point we haven't introduced `Result` (or at least not in any detail).
This allows the students to just focus on writing the pattern matches on
`Expression` and `Op`, and allows the exercise to be shorter (and I
think we need to free up some time where we can, my classes often run
long and cut into how much time students have for exercises).
  • Loading branch information
randomPoison authored Dec 16, 2024
1 parent f60513e commit 2bae363
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 43 deletions.
7 changes: 1 addition & 6 deletions src/pattern-matching/exercise.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
minutes: 30
minutes: 20
---

# Exercise: Expression Evaluation
Expand Down Expand Up @@ -57,11 +57,6 @@ the course. An expression can be "boxed" with `Box::new` as seen in the tests.
To evaluate a boxed expression, use the deref operator (`*`) to "unbox" it:
`eval(*boxed_expr)`.

Some expressions cannot be evaluated and will return an error. The standard
[`Result<Value, String>`](https://doc.rust-lang.org/std/result/enum.Result.html)
type is an enum that represents either a successful value (`Ok(Value)`) or an
error (`Err(String)`). We will cover this type in detail later.

Copy and paste the code into the Rust playground, and begin implementing `eval`.
The final product should pass the tests. It may be helpful to use `todo!()` and
get the tests to pass one-by-one. You can also skip a test temporarily with
Expand Down
50 changes: 13 additions & 37 deletions src/pattern-matching/exercise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,27 @@ enum Expression {
// ANCHOR_END: Expression

// ANCHOR: eval
fn eval(e: Expression) -> Result<i64, String> {
fn eval(e: Expression) -> i64 {
// ANCHOR_END: eval
match e {
Expression::Op { op, left, right } => {
let left = match eval(*left) {
Ok(v) => v,
Err(e) => return Err(e),
};
let right = match eval(*right) {
Ok(v) => v,
Err(e) => return Err(e),
};
Ok(match op {
let left = eval(*left);
let right = eval(*right);
match op {
Operation::Add => left + right,
Operation::Sub => left - right,
Operation::Mul => left * right,
Operation::Div => {
if right == 0 {
return Err(String::from("division by zero"));
} else {
left / right
}
}
})
Operation::Div => left / right,
}
}
Expression::Value(v) => Ok(v),
Expression::Value(v) => v,
}
}

// ANCHOR: tests
#[test]
fn test_value() {
assert_eq!(eval(Expression::Value(19)), Ok(19));
assert_eq!(eval(Expression::Value(19)), 19);
}

#[test]
Expand All @@ -81,7 +69,7 @@ fn test_sum() {
left: Box::new(Expression::Value(10)),
right: Box::new(Expression::Value(20)),
}),
Ok(30)
30
);
}

Expand All @@ -107,7 +95,7 @@ fn test_recursion() {
left: Box::new(term1),
right: Box::new(term2),
}),
Ok(85)
85
);
}

Expand All @@ -119,35 +107,23 @@ fn test_zeros() {
left: Box::new(Expression::Value(0)),
right: Box::new(Expression::Value(0))
}),
Ok(0)
0
);
assert_eq!(
eval(Expression::Op {
op: Operation::Mul,
left: Box::new(Expression::Value(0)),
right: Box::new(Expression::Value(0))
}),
Ok(0)
0
);
assert_eq!(
eval(Expression::Op {
op: Operation::Sub,
left: Box::new(Expression::Value(0)),
right: Box::new(Expression::Value(0))
}),
Ok(0)
);
}

#[test]
fn test_error() {
assert_eq!(
eval(Expression::Op {
op: Operation::Div,
left: Box::new(Expression::Value(99)),
right: Box::new(Expression::Value(0)),
}),
Err(String::from("division by zero"))
0
);
}
// ANCHOR_END: tests
Expand Down

0 comments on commit 2bae363

Please sign in to comment.