You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/jank-test-suite-initial-run-results.md
+24-46Lines changed: 24 additions & 46 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -58,7 +58,7 @@ static public short shortCast(short x){
58
58
// etc. for the remaining primitive numeric types
59
59
```
60
60
61
-
Now, is it turns out, ClojureCLR is missing the overloads for `shortCast`, having only the one taking an `object`. This is an efficiency matter, and I will fix it. (For the majore conversions, `intCast`, `longCast`, `doubleCast`, and `floatCast`, the overloads are present.)
61
+
Now, is it turns out, ClojureCLR is missing the overloads for `shortCast`, having only the one taking an `object`. This is an efficiency matter, and I will fix it. (For the major conversions, `intCast`, `longCast`, `doubleCast`, and `floatCast`, the overloads are present.)
62
62
63
63
The variant of interest here is for the `Object` case. In ClojureCLR, this is
64
64
@@ -189,7 +189,7 @@ The root cause here is that on the CLR, `System.String` implements `IConvertible
189
189
ClojureCLR was failing the test for `(parse-double "Infinity")` and `(parse-double "-Infinity")`.
190
190
`parse-double` mostly is a wrapper for `Double.Parse`. Upon reading the doc for that method, one finds that it is indeed supposed to handle strings representing positive and negative infinity. However, the values it looks for are culture-dependent, specifically the values of `NumberFormatInfo.PositiveInfinitySymbol` and `NumberFormatInfo.NegativeInfinitySymbol`. In the `InvariantCulture`, these are "Infinity" and "-Infinity". However, in my culture (en-US), they are "∞" and "-∞". This is not the first time I've been bitten by this. In fact, take a close look through the code above to see it in use.
191
191
192
-
> Change the `Parse` calls to use `InvariantCulture`.
192
+
> Change the `Parse` calls to use `InvariantCulture`. (DONE!)
193
193
194
194
## Quot-idian problems
195
195
@@ -244,7 +244,7 @@ In both instances, `*math-context*` is null, so the difference will be found in
244
244
245
245
`java.math.BigDecimal` is defined by the JVM. We can look at its doc:
246
246
247
-
> Returns a BigDecimal whose value is the integer part of (this / divisor). Since the integer part of the exact quotient does not depend on the rounding mode, the rounding mode does not affect the values returned by this method. The preferred scale of the result is (this.scale() - divisor.scale()). An ArithmeticException is thrown if the integer part of the exact quotient needs more than mc.precision digits.
247
+
> Returns a BigDecimal whose value is the integer part of (this / divisor). Since the integer part of the exact quotient does not depend on the rounding mode, the rounding mode does not affect the values returned by this method. The preferred scale of the result is (this.scale() - divisor.scale()). An ArithmeticException is thrown if the integer part of the exact quotient needs more than mc.precision digits. (DONE!)
248
248
249
249
For ClojureCLR, it defines its own `BigDecimal` class. We can look at the source. Bizarrely, or perhaps just ironically, I took the implementation of `DivideInteger` from the OpenJDK algorithm!
250
250
@@ -312,7 +312,7 @@ should be:
312
312
if (quotient._exp<0)
313
313
```
314
314
315
-
>BUG:Fixtheerror.
315
+
>BUG:Fixtheerror. (DONE!)
316
316
317
317
## Rationalize this
318
318
@@ -376,7 +376,7 @@ BigDecimal bx = x as BigDecimal
376
376
377
377
Ifyoulookaroundthecodeinthisarea, you'll see plenty of places where I do this properly. This one just slipped through.
378
378
379
-
>BUG:Fixtheerror.
379
+
>BUG:Fixtheerror. (DONE!)
380
380
381
381
Andwhilewearebeingrational:
382
382
@@ -420,8 +420,7 @@ However, I chose to not to hid the difference in names.
420
420
421
421
## String tests
422
422
423
-
ClojureCLR fails a number of tests for functions in `clojure.string`. I argue below that these tests are semantically invalid.
424
-
423
+
ClojureCLR fails a number of tests for functions in `clojure.string`.
425
424
These tests share the common feature that they pass into a `clojure.string` function such as `capitalize` arguments that are not strings.
426
425
For example,
427
426
@@ -437,46 +436,11 @@ For example,
437
436
(is (=":asdf/asdf" (str/capitalize:asDf/aSdf)))))
438
437
```
439
438
440
-
Now I can just copy the `:cljs` tests for `:cljr` and be done. My question is whether the `:default` tests are proper.
441
-
442
-
I argue this based on the "Design notes for clojure.string" found in the source code. The relevant points:
443
-
444
-
> 1. Strings are objects (as opposed to sequences). As such, the
445
-
string being manipulated is the first argument to a function;
446
-
passing nil will result in a NullPointerException unless
447
-
documented otherwise. If you want sequence-y behavior instead,
448
-
use a sequence.
449
-
450
-
I argue that this implies that the functions in this library are primarily for string (with one adjustment to this statement below).
451
-
452
-
> 2. Functions are generally not lazy, and call straight to host
453
-
methods where those are available and efficient.
454
-
455
-
I argue that "calling straight to host methods" is referring to methods on the implementation of the string class in the platform.
456
-
457
-
> 3. Functions take advantage of String implementation details to
458
-
write high-performing loop/recurs instead of using higher-order
459
-
functions. (This is not idiomatic in general-purpose application
460
-
code.)
461
-
462
-
> 4. When a function is documented to accept a string argument, it
463
-
will take any implementation of the correct *interface* on the
464
-
host platform. In Java, this is CharSequence, which is more
465
-
general than String. In ordinary usage you will almost always
466
-
pass concrete strings. If you are doing something unusual,
467
-
e.g. passing a mutable implementation of CharSequence, then
468
-
thread-safety is your responsibility."
439
+
My question is whether the `:default` tests are proper.
440
+
I discussed the purpose of these test with Jeaye Wilkerson. His intention that the tests should be descriptive of the behavior of each dialect; they are not normative.
469
441
470
-
I argue that "in ordinary usage you will almost always pass concrete strings" is a strong hint that passing non-strings is not ordinary usage.
442
+
Now I can just copy the `:cljs` tests for `:cljr` and be done.
471
443
472
-
It is because the JVM version accepts `CharSequence` arguments that one can get away with passing something like an integer to `capitalize`.
473
-
`capitalize` first calls `toString()` on its argument hence it will work with _any_ argument.
474
-
475
-
There is also a an arguments from consistency. Not all functions in `clojure.string` are as permissive. ClojureJVM throws an exception on `(clojure.string/trim-newline 1)`. One has to inspect the code to determine for which functions ClojureJVM will accept non-string arguments. Thus, this is an artifact of implementation, not part of the contract for the function.
476
-
477
-
Given these arguments, should we be testing on non-string arguments at all? Putting in a `(is (= "1" (str/capitalize 1))` seems to normalize the behavior of passing non-string arguments. I claim that if the function implementations in `clojure.string` were to be changed to reject non-string arguments, the authors would not have broken any contract.
478
-
479
-
IMHO
480
444
481
445
## Some true breakage
482
446
@@ -510,8 +474,22 @@ If instead we define
510
474
511
475
the call `(ok-clone (int-array 3))` works fine.
512
476
513
-
I'm not sure what the best solution is here. Forcing the user to know that the conversion is necessary in one call to `aset` but not the other strikes me as bad. The easiest solution is change `RT.acline` to have return type `Object` instead of `Array`. We get a dynamic callsite in the second `aset` call, but that's probably better than the reflection that takes place in `Array.SetValue`.
477
+
I'm not sure what the best solution is here. Forcing the user to know that the conversion is necessary in one call to `aset` but not the other strikes me as bad.
478
+
<strike>The easiest solution is change `RT.aclone` to have return type `Object` instead of `Array`. We get a dynamic callsite in the second `aset` call, but that's probably better than the reflection that takes place in `Array.SetValue`. </strike>
479
+
480
+
Well, that definitely did not work. The real solution has several parts.
481
+
482
+
- Get rid of `RT.aclone(Array)`
483
+
- Add overloads for `RT.aclone` for all the basic array types used for the other operations: `object[]`, `int[]`, `long[]`, `float[]`, `double[]`, etc.
484
+
- Get rid of `RT.aset(Array a, int idx, object val)`.
485
+
486
+
We will get reflection warnings -- can't be helped. So does ClojureJVM, on the same calls. So I think we are good to go.
487
+
488
+
Oh, and 'gvec.clj` compiles without any warnings. That lib has always been a problem child, particularly for the array functions. So, score.
489
+
490
+
Oh, and all the standard Clojure tests run successfully and with no warnings. Score again.
0 commit comments