[Rust Syllabus] Which Exercises/PRs cover only concepts from chapter 3?

I want to understand where we stand first before we start building new things. We have 10 Open PRs and a wad of existing exercises.

So, my question is: Out of the existing exercises (those Dinesh posted and those in the track already, which ones cover topics in Chapter 3 of the book).

Then, once that’s clear, the next step will be to work out what’s missing (if anything) and agree where those come from (new exercises or copies). Then we can look at Chapter 4 and the more complex things etc. But I want us to get the relevant ones of the existing 10 PRs merged and in a good state before we start working on new things.

I want to just take one step clearly at a time, else we all end up talking at cross-purposes :slight_smile:


(For example, one of the open PRs is on the “Option” concept, but that’s not part of chapter 3 (as far as I can tell), so I want to ignore it for now)

Well, I think it is easier to say which is not covered since Denish covers most of them already. And you can look at my list above for what I think chapter 3 holds. So in my opinion this is what is missing:

  • chars
  • Numeric operators
  • Comments (it is covered by lasagna).

The question is not which concepts from Chapter 3 are covered by the PRs.

The question is which PRs cover (only) concepts from Chapter 3.

Yeah realized that, I think this list is the list of complete:

* Strings are touched upon in chapter 3 but their full introduction happens in chapter 4

It was the fastest way to ignore them rather to understand since I didn’t know Rust to begin with. So as I learned Rust myself, I started implementing concept exercises that I would’ve benefitted from.

It is already implemented but it targets the enums concept. Perhaps you mean to cover the char type

As @iHiD mentioned, I would really appreciate feedback on open PRs, I will try to be prompt with responding and making updates there.

Specifically I request that hints.md, introduction.md, instructions.md be reviewed

I might have used inconsistent identifiers for concepts, for instances for-loops is supposed to be for-in, but I don’t know if there are canonical identifiers across languages.

Another thing that needs work is the rust/concepts at main · exercism/rust · GitHub directory with about.md and introduction.md updated with relevant content.

@isDineshHere (and everyone else) I’d like us not to give feedback on those PRs yet. We will get to that next week, and get them all merged in, but I want to take one step at a time, so everyone can learn about the feedback we want on each PR, rather than lots of people giving potentially conflicting (or incorrect) advice. :slight_smile:

(If we can all learn how to make great Concept Exercise PRs we’ll be able to increase the speed we can add new exercises and all work together to help other tracks etc. But there’s an alignment and knowledge-sharing step that needs to happen to get there. I want us to all have a very clear list of what Concept Exercises should be achieving to get them over the line. But I promise we’ll get to that soon, and get those PRs merged! :))

From my understanding this is how the 5 sub sections on Chapter 3 of the book are currently covered by open PRs and existing concept exercises.

3.1 Variables & Mutability

  • cars-assemble; does a bit of explainer of assignments in introduction.md as well as how to define a mutable variable. I don’t believe its enough to cover the section from the book

Missing

  • variable scope & shadowing
  • constants

3.2 Data Types

  • cars-assemble; covers: integers
  • annalyns-infiltration; covers: booleans
  • phone-number-analysis; covers: tuples
  • bird-watcher; covers: arrays
  • log-levels; covers: strings
  • interest-is-interesting: covers: floating-point-numbers

Missing

  • none

3.3 Functions

  • lucians-luscious-lasagna (solid candidate for functions & comments, might need some touch ups in docs)

Missing

  • none

3.4 Comments

  • none on their own

Missing

  • comments

3.5 Control Flow

  • cars-assemble; covers: if-statements
  • bird-watcher; covers: for-loops
  • interest-is-interesting; covers: while-loops

Missing

Misc

  • high-school-sweethearts; covers: string-formating
    String formatting is used in the book but not explicitly explained in Chapter 3

Out of Scope

  • logs-logs-logs; covers: enums
  • short-fibonacci; covers: vectors
  • semi-structured-logs; covers: enums
  • elons-toys; covers: structs
  • tim-from-marketing; covers: option
  • rpn-calculator; covers: vectors & stacks; requires: enums, match, option, slices
  • role-playing-game; covers: enum, option; requires: match, structs
  • resistor-color; covers: external crates, cargo, iterators, enums
  • magazine-cutout; covers: entry-api, hash-maps; requires: slices, iterators
  • low-power-embedded-game; covers: tuples, tuple-structs; requires: structs
  • health-statistics; covers: structs
  • csv-builder; covers: mutability & ownership
1 Like

@iHiD Here is my answer to your question. I mostly agree with Carl, but am more conservative: fewer PRs made it. Reasoning about the deviations at the bottom. The green ones are definitely covered by Chapter 3.

Notes:

  • I disqualified #1669 High School Sweethearts because it seems the Book (at all) does not cover formatting strings to the extent that is required by the exercise.
  • I disqualified #1673 Log Levels because it deals with strings, whose Rust-peculiarity (subject of Chapter 4) is part of the exercise.
  • #1676 Phone Number Analysis deals only with String specific methods, which might be fine: a normal documentation search problem.

Apologies for the late reply, I have to fix my email notifications from the forum.

I think my list pretty much matches @MatthijsBlom and @isDineshHere . I would include Phone Number Analysis, because it states to deal with tuples, which are covered by chapter 3. I think @isDineshHere did not mention the existing assembly-line, which also fits the criteria (although the examplar uses match, which would not be appropriate at that point).

Side notes:

  • The log-levels PR is confusing to me, because the task seems to be exactly the same as the existing (non-concept) exercise semi-structured-logs.

  • The existing exercise low-power-embedded-game wants to teach tuples (part of chapter 3), but has structs as prerequisite. So that exercise probably won’t fit in the plan of modelling the syllabus after the Rust book.

Including the existing exercises and excluding everything that didn’t make the cut, I’m trying to answer this question as concisely as possible:

Out of the existing exercises (those Dinesh posted and those in the track already, which ones cover topics in Chapter 3 of the book).

Open PRs relevant to the Rust book chapter 3:

Existing exercises relevant to the Rust book chapter 3:

  • assembly-line
  • lucians-luscious-lasagna
1 Like

OK, thank you all.

So let’s get these ones into a good shape. Firstly, I want to start with a very clear pathway:

  • Every exercise has an examplar.rs. This should be the minimum to solve the exercise using the concepts learnt so far. It doesn’t have to be idiomatic. It can contain suboptimal practices. It’s the next step someone takes on their learning journey.
  • By comparing the stub (lib.rs) to the exemplar, we can work out what the introduction needs to teach. The introduction should only contain info about things used in the Exemplar that are not in the stub - ie the code someone writes. Other things can be touched on very loosely. Two examples from Lasagna:
    • We use +, - and * but we can also mention the existence of /. But we shouldn’t dwell on it.
    • We call functions, but we don’t create them. So we don’t need to explain pub or go into any detail about defining functions. But we should say “Rust has functions that are defined by use the keyword fn followed by the name. (You’ll also see visibility modifiers and param/return types, but don’t worry about those for now). You call functions by using the name and passing any arguments in parenthesis.”
  • For extra information that isn’t used in the Exemplar, but is topical, this should go in the after.md (which can be thought of as the introduction.md + extra info). Think of this after.md as more evergreen information on the concept.

So I’m going to go through and make notes on each one. I’m only looking at the exemplar and stub.

Lucians Luscious Lasagna (Basics)

I need to be taught:

  • Calling functions
  • -, +, *
  • Implicit returns

We also use this to cover any other basic information. However, looking at the current introduction there’s loads of unnecessary information in there. For example, we need nothing about let at this stage as it’s not used in the exercise, so let’s pull that out and use it in a different exercise later.

annalyns-infiltration

I need to be taught:

  • !
  • ||, &&
  • Explicit returns
  • That “bool” means “boolean” with a link to info on booleans.

Questions:

  • Why are we using explicit returns here but implicit returns in lasagna. Let’s standardise

cars-assemble

I need to be taught:

  • let
  • what round() is (a method?)
  • constants

interest-is-interesting

I need to be taught:

  • floats
  • if
  • mut
  • while

phone-number-analysis

  • Whatever info.1 is
  • split_at
  • Use of () with let
  • Whatever split_at(1).1 is

Notes:

  • Why does this exercise have semicolons?

Actions

  1. Does everyone agree with that analysis? What have I missed?
  2. When we have consensus on that analysis, Dinesh, refine the introductions to achieve the points, and then tell people when you feel they’re ready for review. Then we can all weigh in.

Sound good?

cars-assemble

There are some missing numeric operators which need to be thought also that concept teaches the basics of int and float.

  • Why are we using explicit returns here but implicit returns in lasagna. Let’s standardize

Different author, different style. We should be using implicit returns in any case (in my opinion).

  • Why does this exercise have semicolons?

Since you need to have semicolons in rust unless it is the last line

  • Whatever info.1 is

A form of indexing

split_at(1).1

Same

  1. Does everyone agree with that analysis? What have I missed?

My thought would be to drop Implicit returns from the first exercise.
This may just be me but I find that teaching let in the basic concept is something that should be done.

I agree Annalyn’s Infiltration should not use return.

Yes, a ‘method’. Beware though: different languages mean different things by this term.

Rust doesn’t have classes or objects and such. As far as I know Rust’s ‘methods’ are just regular functions, except sorta-namespaced and with convenient syntax.

(input * 10.0).round()
// means the same thing as
f64::round(input * 10)

Cars Assemble also uses if, explicit return, and type casts.

Interest is Interesting uses the (void) add-assign operator +=.

This is struct field access. Tuples do not have named fields, but you can still get at them using this syntax. tuple.1 is the tuple’s second field, i.e. element.

That’s actually pattern matching (against a tuple).

A few other exercises have semicolons too.

Rust’s blocks ({ … }) are expressions. They consist of a series of ‘statements’ separated by semicolons, and their value is the value of the last statement. If the last statement is terminated with a semicolon (or, if you will, the last statement is empty) then the value of the block is () (the empty tuple / maximally boring value).

You could see the return keyword as syntactic sugar that makes it convenient to ‘return’ earlier.

I am quite sure that floats are defined in a struct and a struct if not object-oriented, so is it very close. And that struct has methods assigned to it. Methods and functions are different, but in this situation, they should be called methods since they correspond to an instance of a struct.

But of course there are functions as well, but when calling number.method so will it always be a method. Calling f64::round() is a function (I am pretty sure)

I just noticed I missed assembly-line. I’ll add that in later.

I’m having trouble understanding your meaning here.

The difference between Rust’s structs and ‘objects’ in other languages is that the latter ‘physically’ carry (in memory or through some sort of resolution at runtime) references to methods, whereas Rust’s structs don’t. Consequently, the semantic (might not be exactly the right word) differences between ‘functions’ and ‘methods’ that exist in those other languages do not exist in Rust.

Methods in Rust are just associated functions (book, reference) that are annotated with self as their first argument. (Rust Playground)

I suspect the dot syntax was chosen to be reminiscent of the object member access syntax from other languages. It is syntactic sugar for :: – see the reference.

Rust’s official linter, clippy, will complain if explicit returns are used where implicit ones are possible. I want to push our students to use clippy, so I’m strongly in favor of implicit returns.

cars-assemble

I need to be taught (adding to Jeremy, @MatthijsBlom pointed these out already):

  • comparison operators ==, <, <= etc.
  • type casting with as

This is another one of those PRs where the task is almost identical as assembly-line. What’s up with that? Are we going to merge these two?

The rest of Jeremy’s analysis I agree with.

I mean that if you look in the source code, so will float be defined in a struct.

Rust is a bit weird about object-oriented programming in my personal opinion, meaning it doesn’t really act like other object-oriented languages.

As far as I understand so is the major difference between a function and a method, is that functions can only work with the provided data while methods can access all the data provided in the given instance. But as a grand rule, all “functions” defined inside a struct, enum or trait is a method and everything else is a function.

What source code? f64 is a compiler built-in primitive type. Why would it be defined inside a struct?

the major difference between a function and a method, is that functions can only work with the provided data while methods can access all the data provided in the given instance.

I don’t understand. In Rust, every function or method can only access what has been passed into it explicitly. The “method receiver” is just another argument and not treated in a special way.

But as a grand rule, all “functions” defined inside a struct, enum or trait is a method and everything else is a function.

Not really… While OOP languages often define methods right inside the class definition (literally inside the same curly braces), Rust doesn’t do that. Rust’s methods and associated functions are defined in impl blocks, which can be located anywhere. You can even add methods and associated functions to foreign types, ones from the standard library or third party crates, although you need to define a trait for that. Also, you can define “associated functions” in such blocks which do not take a method receiver (self). They are not called methods.

What source code? f64 is a compiler built-in primitive type. Why would it be defined inside a struct?

Other languages use a struct to define data types. But my bad, it was a pure guess, I had personally never seen the definition.

Don’t mean littarly inside.
In oop languages you can also deffine methods outside of a class:

module Methods
    def something
        "ab"
    end
end


class Something
    include Methods
end

(You can also define a method outside of a module or class but then it becomes a class method (which is more or less a function but since in ruby everything is an object so is it a method) and not an instance method).

But also it makes sense that “functions” that don’t take self as a parameter is a function and I meant as a general rule, there are of course expectations.

I don’t understand. In Rust, every function or method can only access what has been passed into it explicitly. The “method receiver” is just another argument and not treated in a special way.

I mean that take for example python:

class Something:
    def __init__(self, abc):
        self.abc = abc
    
    def something(self, abc):
        self.abc = abc

(I know I deserve awards for my very good variable names)
We see here also self, since python can also only access what has been passed explicitly (it can although deal with global variables etc but that doesn’t matter here), but for example I wouldn’t be able to call the method “something” without having an instance of that class. I am pretty sure it is the same in rust when a method has self.