-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add assert macro #5065
Add assert macro #5065
Conversation
Macros no longer take precedence over methods named the same? |
This can be specced, so it should have specs. |
One problem with this implementation is that it causes different type deductions in debug and release mode. a = 5 if true
assert a.is_a? Int32
p a + 7 Works in debug, gets an error in release mode It would be really nice to keep the type limitation but drop the runtime check that it is actually that type. Though then it may be deemed too dangerous even for release mode. |
@oprypin Could this be a solution? ->{ ... }.call |
@Sija i think |
@RX14, |
@oprypin no. foo = "foo" || 1
if foo.is_a?(String) && false
raise "bar"
end
# Foo will always be `String | Int32` here You're correct in that Given we don't use |
Yeah now paste that link on the |
@oprypin but |
@RX14 I couldn't find macros spec, so I didn't add any. Did I miss 'em/should I create new spec? |
@asterite FYI, Swift has both, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I won't object if it eventually gets merged, but my vote goes to reject this.
As Asterite pointed out, proper arguments checks and raising ArgumentError with an explanatory message should be implemented instead.
Just found this macro buried inside of crystal/src/float/printer/cached_powers.cr Lines 167 to 173 in a1e90f0
crystal/src/float/printer/diy_fp.cr Lines 143 to 149 in a1e90f0
crystal/src/float/printer/grisu3.cr Lines 356 to 362 in a1e90f0
crystal/src/float/printer/ieee.cr Lines 195 to 201 in a1e90f0
I'd say it should be either removed or replaced with |
Because Grisu3 it was ported from C as far as I recall. |
@ysbaddaden indeed, yet what should we do about camouflaged |
@ysbaddaden hello? |
Well removed or replace or something, I guess. |
@ysbaddaden Could you be more specific about the next actions? replace or sth is a poor answer and this PR is exactly one of the proposed solutions (replace with |
Sorry, I have no better response. I consider Hence my opinion: drop or replace disguised assertions —and closed this pull request, too. |
I agree with @ysbaddaden, let's just remove |
I am new to Crystal but am glad to see that serious consideration INTRODUCTIONThis reference implementation of a simple assertion facility for RationaleAssertions have an important role to play in application code (see Example
The first
ACKNOWLEDGEMENTSThis implementation is partly based on prior work on assertions in Crystal and on Reference[*1] https://www.cs.ox.ac.uk/files/6184/H2002%20-%20Assertion.pdf REFERENCE IMPLEMENTATIONThis implementation defines two classes (AssertionError and The behavior of assertions is governed by the Crystal "release" flag These .status values can be turned on or off by calling #on or #off, e.g. Here is a more detailed specification: If the "release" flag has been specified, all assertions are identical to true;
The message emitted includes the FILE and LINE number of the assertion,
|
@pkoppstein Turning on and off at runtime is awful because you pay the performance cost of having a check always. Please don't. Having a compile time flag should already cover enough usecase. Having some kind of assertion is good not for validating arguments or checking runtime conditions, but for validating that your own algorithm/logic is correct. It checks the invariants you assumed to be true. If an assert is triggered, it is a bug in the code that contains the assert, not from the user, not from somewhere else. That being said, I don't know how to prevent the feature being misused for checking arguments or other runtime conditions, like Go FAQ mentions. What I once did that is not much different from this: macro if_defined(x)
{% if x.resolve? %}
{{yield}}
{% end %}
end
# inside some method:
if_defined(Spec) do
value.should be 0
end This runs the "assert" only during specs, that is the time to check if everything is behaving as they should. I'm not really sure this is good or bad practice though, but adds to the discussion. |
@lbguilherme wrote:
I'm sorry you didn't take the time to understand the proposal more carefully. As it says quite prominently:
The reference implementation also makes it clear that when the --release flag is specified, the neither the assertion conditions nor the on/off flags are checked, because all that checking has been compiled away. All that's left of each assertion is "true". Now it may be objected that when the
Here it seems you are attempting to impose one particular (and rather narrow) view (or definition) of assertions on everyone. As I sought to emphasize, the proposal seeks to increase flexibility, without taking away the possibility of easily using the assertions in more conventional ways. In fact, the defaults have all been set with such use in mind. Although I believe using the word "assert" in connection with this proposal is appropriate, I am less concerned about the naming than the additional flexibility. As I mentioned, I am fairly new to Crystal and am sure that the proposal can be improved. There are certainly several variants that would be worth discussing. However, my years of experience in a large software development organization have led me to conclude that the additional flexibility that I've mentioned makes a huge and positive difference in multiple ways, as suggested by the already-cited work by Tony Hoare. |
I'm even stronger against assertions than before. I did a bunch of C over the last month, and the language forces you to put assertions almost everywhere because we ASSUME A LOT, and we better have a solution to mark/verify these assumptions (which often catch bugs). In crystal, we bound check and prefer to use safe structures, we have a strong type system with generics (no need to cast pointers), even casting a union type to a more restricted type is safe. Hence we don't assume much, don't manipulate pointers much (use slices), and more importantly don't have to cast pointers to whatever every few lines. We don't have to put assertions to verify claims in Crystal. We only need to properly raise an exception with an explanatory message to report invalid user provided values. Hence: no |
I think the core team is pretty much agreed on this. I'd like to see |
Extracted from #4263 by @will.
/cc @oprypin