How to create a custom element in a block

I know that in ruby ​​we can use a while , but I want to know if I can create a custom one so that I can do something like this:

 custom_while i < 5 do puts i i += 1 end 

I currently have this code:

 def custom_while(condition) loop do break if not condition yield end end i = 0 custom_while i < 5 do puts i i += 1 end 

However, when a condition is evaluated, it always becomes true (since it only takes into account the first estimate i < 5 = true .

Any help would be appreciated!

Note. This is for educational purposes only.

+5
source share
2 answers

You almost had it. So, your problem is that the condition is evaluated only once? Well, what design do we know that we can evaluate as often as we want? That's right: features! So let condition function (or a Proc in Ruby lingo):

 def custom_while(condition) loop do break unless condition.() yield end end i = 0 custom_while -> { i < 5 } do puts i i += 1 end # 0 # 1 # 2 # 3 # 4 

This, unfortunately, does not look as good as in other languages. Ruby's syntax and semantics are aggressively optimized for methods that take exactly 1 "function" as an argument. To do this, Ruby has a special syntactically and semantically lightweight construction, namely blocks. Once you have more than one, you're out of luck.

Compare this with languages ​​that have matching block literals, such as Smalltalk. In Smalltalk, you can write a while:do: method and call it like this:

 i := 0. while: [i < 5] do: [Transcript write: i. i := i + 1]. 

In fact, in Smalltalk, the syntax for blocks is so small that it has no control structures. if / then / else is just a Boolean instance method, for example:

 i % 2 == 0 ifTrue: [Transcript write: "even"] ifFalse: [Transcript write: "odd"]. 

And while is actually a Block instance method, so in fact your example will look like this:

 i := 0. [i < 5] whileTrue: [Transcript write: i. i := i + 1] 

Note. I do not guarantee Smalltalk code, I have not tested it.

+3
source

The problem is that the condition is evaluated before it passes, so it will never change.

Make the condition a function that you evaluate inside the loop, or use a macro to make it cleaner.

+1
source

All Articles