short question for a beginner

greetings to all! I am a beginner in scala and I have a small question, I have to realize a very simple exercise but I have a problem with my loop while, the goal of the exercise is to return the first digit of a number for example for “526” the program must return “5”, since I come from java I do not understand everything, my program works very well in java but not in scala :

def first(n: Int): Int= {
while(n>=10){
n/10
}
n

       }

Hello, and welcome!

In both Java and Scala, just saying n / 10 performs the division and then discards the result. In either language, you must write n = n / 10 to actually change the value of n.

However: in Scala, method parameters are vals and cannot be reassigned. So you’ll either need to add a var to your program, or consider taking a different, more functional approach that doesn’t involve mutation at all; for example, using recursion.

By the way, if you ask another question, please use Markdown syntax so your code is indented. This bit of code was so short I could read it easily anyway, but any longer sample you post ought to be indented properly, to make it easy for others to help you.

2 Likes

There are many answers. The simplest and most obvious is the closest to “wrong way to do it in Scala”:

def first(n: Int): Int = {
  var eventualResult = n
  while (eventualResult >= 10) {
    eventualResult = eventualResult / 10
  }
 eventualResult 
}

Without more surrounding context for why this function exists, the most “correct” answer is to explicitly replace the while loop with recursion which ought to look something like this:

def first(n: Int): Int = {
  @scala.annotation.tailrec
  def recursive(eventualResult: Int = n): Int =
    if (eventualResult < 10)
      eventualResult
    else
      recursive(eventualResult / 10)

  recursive()
}

In the more general case, you should use a pre-existing iterator.

Said in the most general way, using while in Scala is almost ALWAYS a code smell.

1 Like

Is this possible to do the recursivity just with one method ?

Possible yes, at the end of the day there is nothing special in the second method.

If you want you can just call first directly, however, if you want to make first tail-recursive then you need to make it final or that it is declared in an object instead of a class (which you are probably already doing), this because the compiler needs to know it won’t be overridden in order to optimize it.

But in practice, why does it matter to you the presence of that inner method?
That is a common approach because for more advanced use cases you would need to keep track of some state that you do not want to expose to the callers.
Take a look to this for some examples

1 Like

Why not give it a try and see if you get stuck? It’s a great exercise. If you do get stuck, you can show us your code and ask us questions about it.

1 Like

Honestly it’s the first time i see a method in a method like you did, and can you explain me what the “recursive()” do, it just return the result ? But can we just put "eventual result " ?

yea I will do this :smiley: but I began recursivity last day with college, it’s difficult to apprehend at the beginning

Ah ok, Scala (and other languages like Python) allow you to define a method inside a method.

It just like any other method, but that is private to the method that encloses it, so you can think like it is outside like any other method but the only place where it can be called is inside the parent method.
Does that make sense?

It calls the method called recursive, the same way you would call any other method.
Note that, it has a default value for its argument, that is the reason it wasn’t passed.
I actually do not like that, I would have used: recursive(eventualResult = n) instead in the call place and remove the default parameter.

Not sure what you mean with that.

We all been there, keep trying until you can finally solve it by yourself.
Good luck :slight_smile:

Thank you for taking the time to answer me it’s very nice! yes of the blow I understood thanks to your explanations for the double method and the “recursive()” and when I speak of “eventual result” I mean can we put eventual result instead of recursive() to return?

No, because eventualResult doesn’t exist in the scope of first, it only exists in the scope of recursive.

And in general, you should not think in terms of mutation, is not that recursive created and mutated an eventualResult variable. Rather calling recursive with the value n returned a new value, and then you return that value as the result of first.

It may help to do a manual execution of the code:

first(526)
// Initial state

recursive(526)
// By definition of `first` and substitution of `n`

if (526 < 10) 526 else recursive(526 / 10)
// By definition of `recursive` and substitution of `eventualResult`

if (false) 526 else recursive(526 / 10)
// By evaluation of `<`

recursive(526 / 10)
// By evaluation of `if`

recursive(52)
// By evaluation of `/`

if (52 < 10) 52 else recursive(52 / 10)
// By definition of `recursive` and substitution of `eventualResult`

if (false) 52 else recursive(52 / 10)
// By evaluation of `<`

recursive(52 / 10)
// By evaluation of `if`

recursive(5)
// By evaluation of `/`

if (5 < 10) 5 else recursive(5 / 10)
// By definition of `recursive` and substitution of `eventualResult`

if (true) 5 else recursive(5 / 10)
// By evaluation of `<`

5
// By evaluation of `if`

5
// By returning from `recursive`
// (We actually only return one due to the optimization of tail recursion.
// But, you do not need to understand that yet;
// you can just imagine that each recursive call was waiting for the next one to finish,
// As such it needed to return three times, also called frames)

5
// By returning from `first`

5
// Final result of our computation.
1 Like

Yes, you can get your single function implementation just by lifting out recursive and renaming it first.

@annotation.tailrec
def first(n: Int): Int = if (n < 10) n else first(n / 10)

Note the bug when n < 0. For fixing this problem the internal recursive function is quite handy because you want to modify the input, do some work, then modify the result.

def first(n: Int): Int = {
  def sign(m: Int): Int = if (n < 0) -m else m

  @annotation.tailrec
  def worker(m: Int): Int = if (m < 10) m else worker(m / 10)

  // Give worker() a positive input
  // Give result, which will be positive, the correct sign
  sign(worker(sign(n)))
}