[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: assert

Gavin Sinclair

11/17/2004 2:16:00 PM

On Wednesday, November 17, 2004, 8:14:47 PM, Jeff wrote:


> Why not a function like .... #breakpoint? ?

> That would then look very much like an assert.

> b = 5
> breakpoint? b == 5 ? false : true

> Yes/No? I kinda like the question syntax of it.... like should I break?

Well, I think

breakpoint unless b == 5

is clearer. But that's missing the point. Any special method should
have some value over the above statement. Like

breakpoint_unless 'b == 5'

Would be able to use the string 'b == 5' both to test the condition
with eval and to print a message in the console explaining why the
break has occurred.

That is undoubtedly useful functionality. The question is: what
method name is most acceptable? 'breakpoint_unless' is a bit long (I
don't care, but others probably do). Florian likes 'assume' but I
think that's unclear -- at least it's not clear that it concerns
breakpoints. Also I don't like to introduce too many different method
names to the global namespace.

So I thought of introducing a module, giving us

Breakpoint.bp_unless
Breakpoint.bp_if
Breakpoint.bp_trap # for trapping signals

and whatever other smart things people think of. But that's not
clearly a good idea.

But your post gave me this thought:

breakpoint? 'b != 5' # breakpoint if b != 5

The question mark suggests "conditional breakpoint", a term we're all
used to from debuggers, I'm sure. That might be the best idea yet.
I'm just not sure which logic to use:

breakpoint? 'b == 5' # breakpoint unless b == 5

or

breakpoint? 'b == 5' # breakpoint if b == 5

It's if vs unless. I'll have to think about it, and would appreciate
other peoples' thoughts.

Cheers,
Gavin







6 Answers

Michael Neumann

11/17/2004 2:28:00 PM

0

Gavin Sinclair wrote:
> On Wednesday, November 17, 2004, 8:14:47 PM, Jeff wrote:
>
>
>
>>Why not a function like .... #breakpoint? ?
>
>
>>That would then look very much like an assert.
>
>
>>b = 5
>>breakpoint? b == 5 ? false : true
>
>
>>Yes/No? I kinda like the question syntax of it.... like should I break?
>
>
> Well, I think
>
> breakpoint unless b == 5
>
> is clearer. But that's missing the point. Any special method should
> have some value over the above statement. Like
>
> breakpoint_unless 'b == 5'

How about this:

def breakpoint
file, line_no = caller.first.split(':', 2)
reason = File.readlines(file)[line_no.to_i - 1].
strip.sub(/^breakpoint\s+/, '')
p reason
# setup irb session etc.
end

a = 4
breakpoint unless a == 5

This extracts the "unless a == 5" out of the source file. Of course,
that does not work for evaled-code (unless the source-buffer is stored
somewhere and we could access it).

But I'm sure, I'm missing something.

Regards,

Michael


Michael Neumann

11/17/2004 2:50:00 PM

0

Michael Neumann wrote:

> How about this:
>
> def breakpoint
> file, line_no = caller.first.split(':', 2)
> reason = File.readlines(file)[line_no.to_i - 1].
> strip.sub(/^breakpoint\s+/, '')
> p reason
> # setup irb session etc.
> end
>
> a = 4
> breakpoint unless a == 5
>
> This extracts the "unless a == 5" out of the source file. Of course,
> that does not work for evaled-code (unless the source-buffer is stored
> somewhere and we could access it).

This brings me to an idea I've seen in Python test-cases. They use
docstrings before their "asserts", and these docstrings are then use
when the assertion fails. Could we do this as well with comments?

(bad example):

Python:

"""Should be > 5"""
assert(i > 5)

Ruby:

# Should be > 5
assert i > 5

This could avoid the use of the message parameter to the assert_*
methods, which are used very seldom IMO. One disadvantage of comments is
of course, that you can't use #{ ... }.

Regards,

Michael


Florian Gross

11/17/2004 4:11:00 PM

0

Gavin Sinclair wrote:

> The question is: what
> method name is most acceptable? 'breakpoint_unless' is a bit long (I
> don't care, but others probably do). Florian likes 'assume' but I
> think that's unclear -- at least it's not clear that it concerns
> breakpoints.

I actually consider that a feature. The interface isn't bound to
Breakpoints either. It can make sense to have various actions on a
failed assumption and it would be nice if other's could be fit into the
same interface.

> So I thought of introducing a module, giving us
>
> Breakpoint.bp_unless
> Breakpoint.bp_if
> Breakpoint.bp_trap # for trapping signals
>
> and whatever other smart things people think of. But that's not
> clearly a good idea.

The module already exists. (See Breakpoint.activate_drb) However it is a
pain to have methods both inside the Module and in Kernel because that
alters the caller's binding.

> But your post gave me this thought:
>
> breakpoint? 'b != 5' # breakpoint if b != 5
>
> The question mark suggests "conditional breakpoint", a term we're all
> used to from debuggers, I'm sure. That might be the best idea yet.
> I'm just not sure which logic to use:
>
> breakpoint? 'b == 5' # breakpoint unless b == 5
>
> or
>
> breakpoint? 'b == 5' # breakpoint if b == 5

Can we have this as an alias for assume()? I like it better than the
breakpoint_unless/if forms.

Florian Gross

11/17/2004 4:14:00 PM

0

Michael Neumann wrote:

> How about this:
>
> def breakpoint
> file, line_no = caller.first.split(':', 2)
> reason = File.readlines(file)[line_no.to_i - 1].
> strip.sub(/^breakpoint\s+/, '')
> p reason
> # setup irb session etc.
> end
>
> a = 4
> breakpoint unless a == 5
>
> This extracts the "unless a == 5" out of the source file. Of course,
> that does not work for evaled-code (unless the source-buffer is stored
> somewhere and we could access it).

I have extracted run-time information from the source code before
(proc_source.rb -- it finds the source code of a lambda / lambdafied
block) and while it is a nice technique I think the overhead would be
too high in this case. (Plus it will not work with -e which is a minor
annoyance.)

Jean-Hugues ROBERT

11/18/2004 9:59:00 AM

0

At 01:18 18/11/2004 +0900, you wrote:
>Michael Neumann wrote:
>
>>How about this:
>> def breakpoint
>> file, line_no = caller.first.split(':', 2)
>> reason = File.readlines(file)[line_no.to_i - 1].
>> strip.sub(/^breakpoint\s+/, '')
>> p reason
>> # setup irb session etc.
>> end
>> a = 4
>> breakpoint unless a == 5
>>This extracts the "unless a == 5" out of the source file. Of course, that does not work for evaled-code (unless the source-buffer is stored somewhere and we could access it).
>
>I have extracted run-time information from the source code before (proc_source.rb -- it finds the source code of a lambda / lambdafied block) and while it is a nice technique I think the overhead would be too high in this case. (Plus it will not work with -e which is a minor annoyance.)

What overhead are you referring too ?

When an assert bombs, this is an exceptional situation
(supposedly). In such a case I don't mind if the handling
of the exception takes a little while, because I would
rather have more info than less.

BTW: I think that "assert" is a perfect name. That assert()
should re throw an exception or start an irb session should
be a configurable behaviour at run time (i.e. when I am
debugging, it should start an irb session, when in production
it should throw an exception).

There is something I would definitely love to have: The
stack of bindings. So far I can get the binding of the caller
(thanks to some clever code, thanks Florian) and the
"text formatted" caller(). That is not enough. I want to
have a look at the local variables all the way up to the
top of the call stack.

I have begin to develop a work-around but it does not work
yet. It basically uses assert() to store bindings (including
the ones when the assert does not bomb) in a cycling array.
When an assert bombs, it uses the text info from caller() to
try to cross-correlate the recently stored bindings with the
caller() provided call stack. It should work decently in a
mostly single threaded contexts when one calls assert()
frequently enough. This is an heuristic, not 100% reliable.

FWIW.

Yours,

JeanHuguesRobert

-------------------------------------------------------------------------
Web: http://hdl.handle.net/1...
Phone: +33 (0) 4 92 27 74 17



Florian Gross

11/18/2004 3:36:00 PM

0

Jean-Hugues ROBERT wrote:

>>> This extracts the "unless a == 5" out of the source file. Of
>>> course, that does not work for evaled-code (unless the
>>> source-buffer is stored somewhere and we could access it).
>>
>> I have extracted run-time information from the source code before
>> (proc_source.rb -- it finds the source code of a lambda /
>> lambdafied block) and while it is a nice technique I think the
>> overhead would be too high in this case. (Plus it will not work
>> with -e which is a minor annoyance.)
>
> What overhead are you referring too ?
>
> When an assert bombs, this is an exceptional situation (supposedly).
> In such a case I don't mind if the handling of the exception takes a
> little while, because I would rather have more info than less.

Oh, I was not referring to performance overhead -- I was talking about
maintenance overhead. It adds a lot of fragile code (at least if you
want to handle code on STDIN, inside an eval, inside irb and so on
properly). I should have been more clear.

> BTW: I think that "assert" is a perfect name. That assert() should re
> throw an exception or start an irb session should be a configurable
> behaviour at run time (i.e. when I am debugging, it should start an
> irb session, when in production it should throw an exception).

I agree with this except that assert() has a name clash with test/unit.

> There is something I would definitely love to have: The stack of
> bindings. So far I can get the binding of the caller (thanks to some
> clever code, thanks Florian) and the "text formatted" caller(). That
> is not enough. I want to have a look at the local variables all the
> way up to the top of the call stack.

You can have this with a custom C extension or a global trace func. The
problem with the former is that it would likely be quite slow. The
problem with the latter is that it would require a C compiler and that
it might have side effects. (I'm pretty sure that the binding of the
immediate caller can safely be fetched without causing trouble because
eval() does this. I'm not sure about going further up the binding chain.)

> I have begin to develop a work-around but it does not work yet. It
> basically uses assert() to store bindings (including the ones when
> the assert does not bomb) in a cycling array. When an assert bombs,
> it uses the text info from caller() to try to cross-correlate the
> recently stored bindings with the caller() provided call stack. It
> should work decently in a mostly single threaded contexts when one
> calls assert() frequently enough. This is an heuristic, not 100%
> reliable.

Hm, I wonder if it is worth the hassle. Would it not be simpler to just
use a String instead?

I think my current proposed solution to all this looks like this:

- Rename assert() to assume()
- Let assume() take either a block or a code string
- Alias breakpoint?() to assume()

In that case assume() could be omitted in dev-utils though I fear it
might cause some confusion. I still need to get final feedback from
Gavin. (I hope he is not tired of this yet. It grew to quite a long
thread and I am the one to blame for that.)