Super Enums in Rust
Disclaimer: Rust is new to everyone. You will not understand the language in a single lecture.
Ferris the crab!
Memory Safety
- No memory leaks
- No segmentation faults
- Ownership system
Speed
- Compiled and optimized
- Avoids copying data, referencing it instead
- No garbage collector
Zero-Cost Abstractions
Complex data structures and language syntax that has no performance cost at run-time.
Strong Developer Tools
- rustdoc: a documentation tool
- cargo: package manager; builds and runs projects
- rustfmt: code formatter
Less Mistakes
- No more null checks
- No more forgetting to catch exceptions
- No more running off arrays or forgetting to deallocate memory
- No more concurrency issues
- Errors are caught at compile time
Enumerations
An enum is a set of named values called variants, members, or enumerators. An instance of an enum can be assigned any one of the enumerators as a value.
A datatype that represents of many possibilities.
Goal
Construct a card data type that can be printed and compared to others.
Let's start with a really bad example.
struct Card {
int value;
char suit;
void print() {
cout << value << " of "
<< suit << endl;
}
};
int main() {
Card c = Card{2, 'H'};
Card d = Card{11, 'S'};
c.print();
d.print();
}
Card{20, 'B'}
This really sucks.
> ./a.out
2 of H
11 of S
>
struct Card {
int value;
char suit;
Card(int v, char s) {
if (v < 1 && v > 13) {
v = 1;
}
if (s != 'S' && s != 'H' &&
s != 'D' && s != 'C') {
s = 'S';
}
this.value = v;
this.suit = s;
}
};
This still really sucks.
enum Name {
variant1,
variant2,
variant3,
variant4
}
Enums in C++
enum Suit {
Spades, Hearts, Diamonds, Clubs
};
enum Value {
Two, Three, Four, Five, Six,
Seven, Eight, Nine, Ten, Jack,
Queen, King, Ace
};
struct Card {
Suit suit;
Value value;
}
int main() {
Card c = Card{Two, Hearts};
Card d = Card{Jack, Spades};
c.print();
d.print();
}
struct Card {
Suit suit;
Value value;
void print() {
cout << value << " of "
<< suit << endl;
}
}
> ./a.out
0 of 1
9 of 0
>
string valueToString(Value v) {
if (v == Two) return "Two";
if (v == Three) return "Three";
if (v == Four) return "Four";
if (v == Five) return "Five";
if (v == Six) return "Six";
if (v == Seven) return "Seven";
if (v == Eight) return "Eight";
if (v == Nine) return "Nine";
if (v == Ten) return "Ten";
if (v == Jack) return "Jack";
if (v == Queen) return "Queen";
if (v == King) return "King";
return "Ace";
}
string suitToString(Suit s) {
if (s == Spades) return "Spades";
if (s == Hearts) return "Hearts";
if (s == Diamonds) return "Diamonds";
return "Clubs";
}
int main() {
Card c = Card{Two, Hearts};
Card d = Card{Jack, Spades};
c.print();
d.print();
}
struct Card {
Suit suit;
Value value;
void print() {
cout << valueToString(value)
<< " of "
<< suitToString(suit)
<< endl;
}
}
> ./a.out
Two of Hearts
Jack of Spades
>
struct Card {
// Properties
bool higher_than(Card c) {
return value > c.value;
}
}
int main() {
Card c = Card{Two, Hearts};
Card d = Card{Jack, Spades};
if (c.higher_than(d)) {
cout << "c is better than d" << endl;
} else {
cout << "c is not better than d" << endl;
}
}
enum Value {
Two, Three, Four, Five, Six,
Seven, Eight, Nine, Ten, Jack,
Queen, King, Ace
};
enum Value {
Two = 2, Three = 3, Four = 4, Five = 5,
Six = 6, Seven = 7, Eight = 8, Nine = 9,
Ten = 10, Jack = 11, Queen = 12,
King = 13, Ace = 1
};
#include <iostream>
#include <string>
using namespace std;
enum Value {
Two = 2, Three = 3, Four = 4, Five = 5, Six = 6,
Seven = 7, Eight = 8, Nine = 9, Ten = 10, Jack = 11,
Queen = 12, King = 13, Ace = 1
};
string valueToString(Value v) {
if (v == Two) return "Two";
if (v == Three) return "Three";
if (v == Four) return "Four";
if (v == Five) return "Five";
if (v == Six) return "Six";
if (v == Seven) return "Seven";
if (v == Eight) return "Eight";
if (v == Nine) return "Nine";
if (v == Ten) return "Ten";
if (v == Jack) return "Jack";
if (v == Queen) return "Queen";
if (v == King) return "King";
return "Ace";
}
enum Suit {
Spades, Hearts, Diamonds, Clubs
};
string suitToString(Suit s) {
if (s == Spades) return "Spades";
if (s == Hearts) return "Hearts";
if (s == Diamonds) return "Diamonds";
return "Clubs";
}
struct Card {
Value value;
Suit suit;
void print() {
cout << valueToString(value) << " of " << suitToString(suit) << endl;
}
bool higher_than(Card c) {
return value > c.value;
}
};
int main() {
Card c = Card{Two, Hearts};
Card d = Card{Jack, Spades};
c.print();
d.print();
if (c.higher_than(d)) {
cout << "c is better than d" << endl;
} else {
cout << "c is not better than d" << endl;
}
}
C++ Enums
Pros
Cons
- More restrictive than integers and strings
- Can't insert a wrong value
- Every variant is a number
- Every variant is a number
- Every variant is brought into scope
- Converting to strings is a nightmare
- Can't have methods
enum Name {
variant1,
variant2,
variant3,
variant4
}
Enums in Java
enum Value {
Two, Three, Four, Five, Six,
Seven, Eight, Nine, Ten, Jack,
Queen, King, Ace
}
enum Suit {
Spades, Hearts, Diamonds, Clubs
}
static class Card {
Value value;
Suit suit;
public Card(Value v, Suit s) {
value = v;
suit = s;
}
}
public static void main(String[] args) {
Card c = new Card(Value.Two, Suit.Hearts);
Card d = new Card(Value.Jack, Suit.Spades);
}
static class Card {
// Properties
// Constructor
public void print() {
System.out.println(this.value.toString()
+ " of " + this.suit.toString());
}
}
public static void main(String[] args) {
Card c = new Card(Value.Two, Suit.Hearts);
Card d = new Card(Value.Jack, Suit.Spades);
c.print();
d.print();
}
> java main
Two of Hearts
Jack of Spades
>
static public int valueOf(Value v) {
if (v == Value.Two) return 2;
if (v == Value.Three) return 3;
if (v == Value.Four) return 4;
if (v == Value.Five) return 5;
if (v == Value.Six) return 6;
if (v == Value.Seven) return 7;
if (v == Value.Eight) return 8;
if (v == Value.Nine) return 9;
if (v == Value.Ten) return 10;
if (v == Value.Jack) return 11;
if (v == Value.Queen) return 12;
if (v == Value.King) return 13;
return 1;
}
static class Card {
// Properties
// Methods
public boolean higherThan(Card c) {
return valueOf(this.value) > valueOf(c.value);
}
}
public static void main(String[] args) {
Card c = new Card(Value.Two, Suit.Hearts);
Card d = new Card(Value.Jack, Suit.Spades);
if (c.higherThan(d)) {
System.out.println("c is better than d");
} else {
System.out.println("c is not better than d");
}
}
class main {
enum Value {
Two, Three, Four, Five, Six,
Seven, Eight, Nine, Ten, Jack,
Queen, King, Ace
}
static public int valueOf(Value v) {
if (v == Value.Two) return 2;
if (v == Value.Three) return 3;
if (v == Value.Four) return 4;
if (v == Value.Five) return 5;
if (v == Value.Six) return 6;
if (v == Value.Seven) return 7;
if (v == Value.Eight) return 8;
if (v == Value.Nine) return 9;
if (v == Value.Ten) return 10;
if (v == Value.Jack) return 11;
if (v == Value.Queen) return 12;
if (v == Value.King) return 13;
return 1;
}
enum Suit {
Spades, Hearts, Diamonds, Clubs
}
static class Card {
Value value;
Suit suit;
public Card(Value v, Suit s) {
value = v;
suit = s;
}
public void print() {
System.out.println(this.value.toString()
+ " of " + this.suit.toString());
}
public boolean higherThan(Card c) {
return valueOf(this.value) > valueOf(c.value);
}
}
public static void main(String[] args) {
Card c = new Card(Value.Two, Suit.Hearts);
Card d = new Card(Value.Jack, Suit.Spades);
c.print();
d.print();
if (c.higherThan(d)) {
System.out.println("c is better than d");
} else {
System.out.println("c is not better than d");
}
}
}
Java Enums
Pros
Cons
- Easily converted to strings
- Aren't numbers
- Variants are scoped by the name of the enum
- Variants are scoped by the name of the enum
- Can't have methods easily
- Can't guarantee check on all variants
enum Name {
variant1,
variant2,
variant3,
variant4
}
Enums in Rust
Rust Syntax in 4.5 Minutes
Hello World!
fn main() {
println!("Hello, world!");
}
Variables and Mutability
fn main() {
let hourly_rate = 10;
let mut money = 0;
let name = "Bob";
money += hourly_rate * 2;
println!("{} made {} dollars today.",
name,
money
)
}
> ./example
Bob made 20 dollars today.
>
Conditionals
fn main() {
println!("Would you like some cookies?");
let num_cookies = 10;
if num_cookies > 0 {
println!("They look delicious!");
} else {
println!("Where are they?");
}
}
Type Annotation and Casting
fn main() {
let x: i32 = 50;
let y: i32 = 20;
let z: i32 = x - y;
let m_pi: f32 = 3.14159;
let e_pi = m_pi as i32;
}
Datatypes
i8 i16 i32 i64 i128 isize
u8 u16 u32 u64 u128 usize
Integers
Booleans
Characters
Floats
bool
char
f32, f64
Strings and String Slices
fn main() {
let me: String = String::from("Dave");
let him: &str = "Ryan";
println!("{} has methods. {} does not.",
me,
him,
)
let enhance: String = him.to_string();
println!("Now {} has methods.");
}
Loops
fn main() {
let mut i = 0;
while i != 5 {
println!("{}", i);
i++;
}
}
fn main() {
for i in 0..5 {
println!("{}");
}
}
Vectors
fn main() {
let mut profs: Vec<&str> = vec![
"Gupta", "Chen", "Linos",
"Sorenson", "Rybarczyk"
];
profs.push("Partenheimer");
for prof in profs {
println!("{} is the best!", prof);
}
println!("But {} is my favorite.", profs[0]);
}
Functions
fn can_ride(age: u32, height: f32) -> bool {
if age >= 10 || height > 3.5 {
return true;
} else {
return false;
}
}
fn main() {
let allowed = can_ride(8, 4.1);
}
Return Values
fn main() {
let her_age = 17;
// my_status is dating or single
let my_status = if her_age < 18 {
"single"
} else {
"dating"
};
}
Return Values
fn can_ride(age: u32, height: f32) -> bool {
if age >= 10 || height > 3.5 {
return true;
} else {
return false;
}
}
fn can_ride(age: u32, height: f32) -> bool {
if age >= 10 || height > 3.5 {
true
} else {
false
}
}
fn can_ride(age: u32, height: f32) -> bool {
age >= 10 || height > 3.5
}
Structs
struct Fish {
num_eyes: i32,
color: String,
}
fn main() {
let gregory = Fish {
num_eyes = 5,
color = "red".to_string(),
};
}
impl Fish {
// static
fn new(e: i32, c: String) -> Fish {
Fish {
num_eyes: e,
color: c,
}
}
// read only
fn print(&self) {
println!("I'm {} with {} eyes.",
self.color,
self.num_eyes,
)
}
// read and mutate
fn remove_eyes(&mut self) {
self.num_eyes = 0;
}
}
fn main() {
let mut gregory = Fish::new(
5, "red".to_string()
);
gregory.print();
gregory.remove_eyes();
gregory.print();
}
> ./example
I'm red with 5 eyes.
I'm red with 0 eyes.
>
That's time!
enum Name {
variant1,
variant2,
variant3,
variant4
}
Enums in Rust
enum Value {
Two, Three, Four, Five, Six,
Seven, Eight, Nine, Ten, Jack,
Queen, King, Ace
}
enum Suit {
Spades, Hearts, Diamonds, Clubs
}
struct Card {
suit: Suit,
value: Value,
}
fn main() {
let c = Card { value: Value::Two, suit: Suit::Hearts };
let d = Card { value: Value::Jack, suit: Suit::Spades };
}
fn main() {
use Value::*;
use Suit::*;
let c = Card { value: Two, suit: Hearts };
let d = Card { value: Jack, suit: Spades };
}
struct Card {
suit: Suit,
value: Value,
}
impl Card {
fn print(&self) {
println!("{:?} of {:?}", self.value, self.suit);
}
}
fn main() {
use Value::*;
use Suit::*;
let c = Card { value: Two, suit: Hearts };
let d = Card { value: Jack, suit: Spades };
c.print();
d.print();
}
impl Value {
fn to_int(&self) -> i32 {
use Value::*;
match self {
Two => 2,
Three => 3,
Four => 4,
Five => 5,
Six => 6,
Seven => 7,
Eight => 8,
Nine => 9,
Ten => 10,
Jack => 11,
Queen => 12,
King => 13,
Ace => 1,
}
}
}
impl Card {
fn higher_than(&self, c: Card) -> bool {
self.value.to_int() > c.value.to_int()
}
}
fn main() {
use Value::*;
use Suit::*;
let c = Card { value: Two, suit: Hearts };
let d = Card { value: Jack, suit: Spades };
c.print();
d.print();
if c.higher_than(d) {
println!("c is better than d");
} else {
println!("c is not better than d");
}
}
#[derive(Debug)]
enum Value {
Two, Three, Four, Five, Six,
Seven, Eight, Nine, Ten, Jack,
Queen, King, Ace
}
impl Value {
fn to_int(&self) -> i32 {
use Value::*;
match self {
Two => 2,
Three => 3,
Four => 4,
Five => 5,
Six => 6,
Seven => 7,
Eight => 8,
Nine => 9,
Ten => 10,
Jack => 11,
Queen => 12,
King => 13,
Ace => 1,
}
}
}
#[derive(Debug)]
enum Suit {
Spades, Hearts, Diamonds, Clubs
}
struct Card {
suit: Suit,
value: Value,
}
impl Card {
fn print(&self) {
println!("{:?} of {:?}", self.value, self.suit);
}
fn higher_than(&self, c: Card) -> bool {
self.value.to_int() > c.value.to_int()
}
}
fn main() {
use Value::*;
use Suit::*;
let c = Card { value: Two, suit: Hearts };
let d = Card { value: Jack, suit: Spades };
c.print();
d.print();
if c.higher_than(d) {
println!("c is better than d");
} else {
println!("c is not better than d");
}
}
Rust Enums
Pros
Cons
- Opt in to bring variants into scope
- Can have methods
- Aren't numbers
- Easy conversion to strings
- Match statement ensures comparisons can't go wrong
- As powerful at structs
Structs vs. Enums
enum Name {
variant1,
variant2,
variant3,
variant4
}
struct Name {
key1: type1;
key2: type2;
key3: type3;
key4: type4;
}
simultaneous properties
exactly one property
stores data for each property
no data stored
this really sucks
Integers
Rationals
Reals
Complex
Number
enum Number {
Integer(i32),
Rational(i32, i32),
Real(f32),
Complex(f32, f32),
}
enum Number {
Integer,
Rational,
Real,
Complex,
}
enum Name {
variant1(type1),
variant2(type2),
variant3(type3),
variant4(type4)
}
Enums in Rust
enum Number {
Integer(i32),
Rational(i32, i32),
Real(f32),
Complex(f32, f32),
}
fn main() {
let a = Number::Integer(-4);
let b = Number::Rational(7, 8);
let c = Number::Real(3.141592653);
let d = Number::Complex(-1.0, 2.0);
}
impl Number {
fn print(&self) {
use Number::*;
match self {
Integer(n) => println!("{}", n),
Rational(n, d) => println!("{}/{}", n, d),
Real(x) => println!("{}", x),
Complex(a, b) => println!("{} + {}i", a, b),
}
}
}
impl Number {
fn negate(self) -> Number {
use Number::*;
match self {
Integer(n) => Integer(-n),
Rational(n, d) => Rational(-n, d),
Real(x) => Real(-x),
Complex(a, b) => Complex(-a, -b),
}
}
}
enum Pet {
Dog(String),
Cat(String),
Turtle,
Squirrel
}
fn main() {
let cali = Pet::Cat("Calico".to_string());
let fred = Pet::Turtle;
}
impl Pet {
fn get_breed(&self) -> String {
use Pet::*;
match self {
Dog(breed) => breed.to_string(),
Cat(breed) => breed.to_string(),
_ => "this pet has no breed".to_string(),
}
}
}
> ./example
My pet's breed is Calico
My pet's breed is this pet has no breed
>
fn main() {
let cali = Pet::Cat("Calico".to_string());
let fred = Pet::Turtle;
let pets = vec![cali, fred];
for pet in pets {
println!("My pet's breed is {}", pet.get_breed());
}
}
impl Pet {
fn has_breed(&self) -> bool {
use Pet::*;
match self {
Turtle => false,
Squirrel => false,
_ => true,
}
}
}
fn main() {
let cali = Pet::Cat("Calico".to_string());
let fred = Pet::Turtle;
let pets = vec![cali, fred];
for pet in pets {
if pet.has_breed() {
println!("This pet is a {}", pet.get_breed());
} else {
println!("This pet no breed.")
}
}
}
impl Pet {
fn get_breed(&self) -> Breed {
use Pet::*;
match self {
Dog(breed) => Breed::Has(breed),
Cat(breed) => Breed::Has(breed),
_ => Breed::NoBreed,
}
}
}
enum Breed {
Has(String),
NoBreed
}
Option Type
pub enum Option<T> {
None,
Some(T),
}
Replaces null values!
impl Pet {
fn get_breed(&self) -> Option<String> {
use Pet::*;
match self {
Dog(breed) => Some(breed.to_string()),
Cat(breed) => Some(breed.to_string()),
_ => None,
}
}
}
fn main() {
let cali = Pet::Cat("Calico".to_string());
let fred = Pet::Turtle;
let pets = vec![cali, fred];
for pet in pets {
// Can't work! Can't print Option!
println!("My pet's breed is {}", pet.get_breed());
}
}
fn main() {
let cali = Pet::Cat("Calico".to_string());
let fred = Pet::Turtle;
let pets = vec![cali, fred];
for pet in pets {
match pet.get_breed() {
Some(breed) => println!("My pet is a {}", breed),
None => println!("My pet has no breed"),
}
}
}
enum Pet {
Dog(String),
Cat(String),
Turtle,
Squirrel
}
impl Pet {
fn get_breed(&self) -> Option<String> {
use Pet::*;
match self {
Dog(breed) => Some(breed.to_string()),
Cat(breed) => Some(breed.to_string()),
_ => None,
}
}
}
fn main() {
let cali = Pet::Cat("Calico".to_string());
let fred = Pet::Turtle;
let pets = vec![cali, fred];
for pet in pets {
match pet.get_breed() {
Some(breed) => println!("My pet is a {}", breed),
None => println!("My pet has no breed"),
}
}
}
Integers
Rationals
Reals
Complex
Number
impl Number {
fn into_complex(&self) -> Number {
use Number::*;
match *self {
Integer(n) => Complex(n as f32, 0.0),
Rational(n, d) => {
let f = n as f32 / d as f32;
Complex(f, 0.0)
},
Real(x) => Complex(x, 0.0),
Complex(a, b) => Complex(a, b),
}
}
}
impl Number {
fn into_real(&self) -> Number {
use Number::*;
match *self {
Integer(n) => Real(n as f32),
Rational(n, d) => {
let f = n as f32 / d as f32;
Real(f)
},
Real(x) => Real(x),
Complex(a, b) => Real(a), // gross
}
}
}
Error Handling in Java
class main {
public static void main(String[] args) {
int a = 10, b = 0;
int quotient;
try {
// would crash program
quotient = a / b;
} catch (Exception ex) {
// but its caught and dealt with here
System.out.println("Divided by 0!");
System.out.println(ex.getMessage());
}
System.out.println("a / b = " + quotient);
}
}
class main {
public static void main(String[] args) {
int a = 10, b = 0;
int quotient;
try {
// would crash program
quotient = Integer.division(a, b);
} catch (Exception ex) {
// but its caught and dealt with here
System.out.println("Divided by 0!");
System.out.println(ex.getMessage());
}
System.out.println("a / b = " + quotient);
}
}
class main {
public static void main(String[] args) {
int a = 10, b = 0;
int product;
try {
// can NEVER crash program
product = Integer.product(a, b);
} catch (Exception ex) {
// none of this will ever be run
System.out.println("Error!");
System.out.println(ex.getMessage());
}
System.out.println("a * b = " + product);
}
}
Result Type
pub enum Result<T, E> {
Ok(T),
Err(E),
}
Replaces exception handling!
No more try-catching!
impl Number {
fn into_real(&self) -> Result<Number, String> {
use Number::*;
match *self {
Integer(n) => Ok(Real(n as f32)),
Rational(n, d) => {
let f = n as f32 / d as f32;
Ok(Real(f))
},
Real(x) => Ok(Real(x)),
Complex(a, b) => {
if b == 0.0 {
Ok(Real(a))
} else {
Err("Imaginary part is nonzero".to_string())
}
},
}
}
}
fn main() {
let a = Number::Integer(-4);
let b = Number::Rational(7, 8);
let c = Number::Real(3.141592653);
let d = Number::Complex(-1.0, 2.0);
let nums = vec![a, b, c, d];
for num in &nums {
// No try catch needed! This will NEVER fail!
let z = num.into_complex();
z.print();
}
}
fn main() {
let a = Number::Integer(-4);
let b = Number::Rational(7, 8);
let c = Number::Real(3.141592653);
let d = Number::Complex(-1.0, 2.0);
let nums = vec![a, b, c, d];
for num in &nums {
// Doesn't work! Can't ignore failure!
// num.into_real().print();
match num.into_real() {
Ok(x) => x.print(),
Err(s) => println!("{}", s),
}
}
}
#[derive(Clone, Copy)]
enum Number {
Integer(i32),
Rational(i32, i32),
Real(f32),
Complex(f32, f32),
}
impl Number {
fn print(&self) {
use Number::*;
match self {
Integer(n) => println!("{}", n),
Rational(n, d) => println!("{}/{}", n, d),
Real(x) => println!("{}", x),
Complex(a, b) => println!("{} + {}i", a, b),
}
}
fn negate(self) -> Number {
use Number::*;
match self {
Integer(n) => Integer(-n),
Rational(n, d) => Rational(-n, d),
Real(x) => Real(-x),
Complex(a, b) => Complex(-a, -b),
}
}
fn into_complex(&self) -> Number {
use Number::*;
match *self {
Integer(n) => Complex(n as f32, 0.0),
Rational(n, d) => {
let f = n as f32 / d as f32;
Complex(f, 0.0)
},
Real(x) => Complex(x, 0.0),
Complex(a, b) => Complex(a, b),
}
}
// Talk about why we can't just return REAL
fn into_real(&self) -> Result<Number, String> {
use Number::*;
match *self {
Integer(n) => Ok(Real(n as f32)),
Rational(n, d) => {
let f = n as f32 / d as f32;
Ok(Real(f))
},
Real(x) => Ok(Real(x)),
Complex(a, b) => {
if b == 0.0 {
Ok(Real(a))
} else {
Err("Imaginary part is nonzero".to_string())
}
},
}
}
}
fn main() {
let a = Number::Integer(-4);
let b = Number::Rational(7, 8);
let c = Number::Real(3.141592653);
let d = Number::Complex(-1.0, 2.0);
let nums = vec![a, b, c, d];
for num in &nums {
num.print();
}
println!();
for num in &nums {
// No try catch needed! This will NEVER fail!
num.into_complex().print();
}
println!();
for num in &nums {
// Doesn't work!
// num.into_real().print();
match num.into_real() {
Ok(x) => x.print(),
Err(s) => println!("{}", s),
}
}
}
Let's Write Wumpus!
pub enum Player {
Alive { arrows: usize, location: usize },
Dead(String),
Win,
}
enum Hazard {
Wumpus,
Bats,
Pitfall,
}
struct Room {
adjacent: [usize; 3],
hazard: Option<Hazard>,
}
pub struct Cave {
rooms: Vec<Room>,
}
pub enum Action {
Move(usize),
Shoot(usize),
Quit,
Help,
}
use std::io;
fn main() {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).unwrap();
let x = buffer.trim().parse::<i32>().unwrap();
}
#include <iosteam>
using namespace std;
int main() {
int x;
cin >> x;
}
import java.util.Scanner;
class main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int x = input.nextInt();
}
}
super_enums
By rutrum
super_enums
A talk given through Butler University ACM on November 13th 2019.
- 433