It'd be easier to work with the Fraction objects if they typing was stricter and we had an interface.
As mentioned in the related issues, there are some things we could improve:
- Numerator and denominator could be typed as integers. They're already stored in the database as such and in the config as well.
- As we're using bcmath, the fraction values could be hinted to string, not float.
| Comment | File | Size | Author |
|---|---|---|---|
| #20 | 3100039-17_20-do-not-test.txt | 785 bytes | deaom |
| #20 | 3100039-20.patch | 10.43 KB | deaom |
| #18 | 3100039-12_17.diff | 6.66 KB | deaom |
| #17 | 3100039-17.patch | 10.41 KB | deaom |
| #12 | 3100039-12.patch | 9.39 KB | deaom |
Comments
Comment #2
zvonimirrHere is a patch I've put together.
Comment #3
zvonimirrComment #4
pcambraThanks!!
Patch seems to be missing FractionInterface.php file?
*I think* numerator/denominator should not be casted to string.
Not sure why tests are failing, but there are some coding standard notices that can be reviewed in https://www.drupal.org/pift-ci-job/1533969
Comment #5
pcambraThe only question pending here, probably for @m.stenta is whether we want the numerator and denominator as ints or strings.
Comment #6
m.stentaI think this is why the tests are failing. I get
Fatal error: Interface 'Drupal\fraction\FractionInterface' not found in /var/www/html/modules/fraction/src/Fraction.php on line 8if I try to runfraction_from_decimal(0.5);@zvonimirr00: Do you have a
FractionInterface.phpfile that you forgot to include in the patch?Comment #7
m.stentaI think we need to work under the assumption that this
Fractionclass is working with strings as much as possible.Currently the class accepts either strings or integers in
setNumerator()andsetDenominator(), but it always stores them as strings internally (casting them before saving them to$this->numeratorand$this->denominator). It also is flexible in the types that are accepted infromDecimal(). This is intentional.Strings are used consistently through the class because it uses BCMath to perform arithmetic operations (when it is available, falling back to standard PHP int/float arithmetic if not). BCMath functions work with strings, so if we store numerator and denominator as integers internally, they will need to be cast to strings before being used in BCMath operations. Also, the methods
toDecimal(),gcd(), andbcRound()all return strings. Again, because the assumption is that the class is using BCMath. Some decimal values are not representable as floats, so strings provide more possibility.So, I think we should keep the numerator and denominator represented as strings internally. And we should keep the flexibility of accepting multiple types in
setNumerator(),setDenominator(), andfromDecimal(), and not limit to string or integer.I think that means the scope of this issue's changes will be more limited. Hopefully that doesn't negate all of the benefits you were hoping for with stronger typing @pcambra. What do you think?
Comment #8
kbrodej commentedHi. As the interface from previous patch was missing, I started from scratch. I followed the comment of @m.stenta from #7. As values are always stored as strings I did not typehint signatures, but I added typehints in doc-comment.
Comment #9
kbrodej commentedComment #10
pcambraThanks @kbrodej, let's see what happens with #3110374: Transform the constructor from decimal to be static because it affects this one.
Comment #11
pcambra@kbrodej @zvonimirr00 reopening this because the constructor went in, want to continue working on it?
Comment #12
deaom commentedRe-rolled the patch.
Comment #13
pcambra@DeaOm thanks for the rerroll!
Some nitpicks below
I don't think we want to enforce numerator/denominator
In all these this should be "{@inheritdoc}" instead to follow standards
"the interface"
I think we're doing @package fraction everywhere else
Sets
Gets
Calculates
Calculates
Reduces
Reciprocates
Adds
Substracts
Multiplies
Divides
Comment #14
pcambraA big question to @m.stenta, can we assume that numerator and denominator are always int on the Fraction object? they're stored as int
Comment #15
m.stentaI don't think we want to enforce numerator/denominatorI agree with @pcambra. Changing the constructor so that it does not allow strings is a backwards-incompatible change that could affect downstream code.
And: I think it's OK for the constructor to accept both strings and ints, because generally speaking PHP's automatic type conversion from string to int is pretty straightforward. It does not have the same issues that floats can have. (Please anyone with more knowledge of potential type issues correct me if I'm overlooking something!)
Other things I see:
FractionInterfacethat is added in the patch is explicitly stating that strings or ints are acceptable to pass tosetNumerator()andsetDenominator(). So restricting to ints in the constructor is inconsistent. Changing the constructor to allow both would resolve this inconsistency.protected $numeratorandprotected $denominatorproperties as@var string. That conflicts with both the constructor and the interface, as described above. Changing this to allow ints as well would resolve this inconsistency.FractionInterface,getNumerator()andgetDenominator()both declare that they are returning strings. They may also return ints. The docblock should be updated to reflect this.FractionInterfaceneeds to be updated to reflect the changes from #3110374: Transform the constructor from decimal to be static:fromDecimal()method, but not the newcreateFromDecimal()method.fromDecimal()appears to be correct inFractionInterface, but it needs to be removed/replaced fromFraction.phpwith{@inheritdoc}like all the others.fromDecimal()inFractionInterfaceneeds to include the deprecation notice.Hopefully that's everything! I will give it another thorough review once these changes are made to make sure we didn't miss anything.
Thanks everyone for helping get this organized!
Comment #16
m.stentaAlso (super small nit pick): looks like the patch is adding an extra newline under the constructor. I don't think that should be there (unless there's a new standard for that that I'm unaware of?)
Comment #17
deaom commentedHi @pcambra and @m.stenta, here is the updated patch and interdiff. I think I corrected everything that was mentioned in the comments.
Comment #18
deaom commentedRemoving the interdiff and adding it again but this time without testing it.
Comment #19
pcambraThanks @DeaOm!
Just one thing on my side:
Could we call these variables $numerator and $denominator? $value is misleading IMHO
As a side note, I always post interdiffs as .txt files to avoid triggering the testbot, another option is to include "do-not-test" as part of the filename, see https://www.drupal.org/node/332678
Comment #20
deaom commentedHi @pcambra, updated patch and interdiff. And thanks for the do-not-test tip, appreciate it.
Comment #21
pcambraThis is looking good to me, leaving @m.stenta the final word :)
Comment #23
m.stentaThanks @DeaOm and @pcambra! This looks good to me!
The only thing that jumped out is that the default parameter values for the constructor were removed. I assume that was a misunderstanding of earlier feedback. We do want to keep those defaults, so I restored them. If there was a reason for removing them, let me know.
Since there were many hands in this process, I'm giving Git's multiple co-author feature a try: https://stackoverflow.com/questions/7442112/how-to-attribute-a-single-co...
@kbrodej will get first author credit for contributing the first full patch including the interface file. Everyone else will be co-authors.
Thanks again everyone!