Re: [rust-dev] sub-grammar for range pattern constants?

2013-04-29 Thread Erik S
On 4/29/2013 2:00 PM, Graydon Hoare wrote:
 Yes. Formalizing and completing the definition of the constant
 expression subgrammar would be extremely valuable. It's one of the
 major high-risk areas remaining the the design space. -Graydon
VHDL is a very different language from Rust (it's a hardware design
language, not a normal programming language), but it has the nicest
constant system I've worked with.

The rule is basically that constant expressions can contain:

Literals (i.e. 5, 0x20)
Expressions that depend on constants  (i.e. 0x5 + 10 * const_k)
Any pure function whose arguments are constant.   (i.e. 5 + f_pure(5,
const_k) )

It's this last rule that is truly beautiful. You can use the same
functions in both constant initialization and run-time code, with only
the requirement that they are pure. Pure functions are ones whose output
depends only on their arguments (and constants). Allowing functions to
initialize constants avoids the whole annoyance in C/C++ where you have
to use macros to make things compile-time const. It also allows a
surprising amount of compile-time optimization.

I don't know how realistic this is for constants in a language like rust
- but it would be very elegant if it could work.

Erik

 
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


[rust-dev] Proposal: Do block with multiple closures (was: Update on I/O progress)

2013-04-29 Thread Erik S
In thinking about how to handle I/O errors, I came up with a system that
needed a do that could take multiple closures (and pass them to
multiple trailing arguments). In thinking about it, this seems
incredibly useful (for non-I/O things), and consistent with how Rust
currently works.

I propose having do (or some related keyword) take an argument that
tells it how many closures it should consume, and pass to that many
trailing arguments. I'm thinking having do take a list of labels, which
are repeated at the blocks, for readability.

So if I don't like the if statement, I could write:

do(:if, :else) if_fun(my_condition) :if {
// if code
}
:else { // else code }


Python has a really useful else block on for loops:

do (:for, :else) for_else(~[1, 2,3]) :for |x| {
  if something(x) {break};
}
:else{
  // Run if for loop didn't break
}


Lisp has the cond statement, which is like a multi-if:

do(:0, :1, :2) cond(~[true, false, false]):0 {
// if zeroth element is true
}
:1 {
// if first is true
}
:2 {
   // if second is true
}


This new do is basically the same as a regular do, except:
Do passes more than one block to the trailing arguments of its function.
Do wraps the return value in an optionX, so we can detect a break;
(which returns None).



The I/O proposal I had is below, if anyone is interested. It has the
advantage of very clean, top-to-bottom code flow in the case where
errors are being handled. It has the disadvantage of adding one level of
parentheses for each I/O call.

I based this on the observation - in my code - that I/O errors are both
expected and handled, and generally not handled in a uniform way. You
simply can't avoid I/O errors - even if you check that a file exists, it
may not by the time you call open(). The same goes for network sockets,
except things are even more unpredictable. 

Each I/O function would take two blocks - error and success. The error
block can return either 1. break - which stops processing, but lets the
task live; 2. io::fail, which kills the task; or 3. a good I/O handle,
which is passed to the success block.


do(:err, :succ) io::open(my-file):err |e| {
   if some-condition(e) {
  do(:err, :succ) io::open(some-other-file)
  :err |_| {io::fail}
  :succ |x|{x}
   }
}
:succ |f| {
   do(:err, :succ) io::write(f) :err {io::fail}
   :succ |f| { f.close(); } // close probably doesn't need to handle errors
}

On both error and success, code flows very nicely top-to-bottom
(skipping error blocks on success). It's easy to see what the argument
is to each success block - it's either the return value from the err
block, or the result of the I/O operation.

That said, the deep nesting makes it pretty ugly.

Thanks,
Erik

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Division and modulo for signed numbers

2013-04-25 Thread Erik S

  
  
Comments inline. I'm glad to see integer division getting this level
of attention. 
Erik

On 4/25/2013 11:12 AM, Matthieu Monrocq
  wrote:


  

  Of course, having an infix syntax would make things
easier: 5 % 3 vs 5 rem 3 vs 5.rem(3), in increasing order of
typed keys (and visual noise for the latter ?).
  

  

I like this a lot. Making "div" and "mod" operators instead of
methods makes them proper, first-class citizens. It also makes them
easy to use in math expressions, which is a big plus. It also makes
them opt-in for developers expecting C-like behavior. 

This looks pretty good to me:
let a = vec[idx mod len]; //safe if len  0
let n = (k + 5) div 10; // precedence rules require parentheses,
just like "/"

I really don't like the [div/mod]_[floor/ceil] methods proposed on
IRC. It makes the ones I care about - [div/mod]_floor - a second
class citizen. Adding "mod" and "div" as operators doesn't feel that
bad to me - these are important and useful, and should exist in a
way that C developers can find them. Making them operators makes
them highly discoverable. 



  
On Thu, Apr 25, 2013 at 6:25 PM,
  Graydon Hoare gray...@mozilla.com
  wrote:
  There are
other questions to answer in this thread. We had a complex
set of conversations yesterday on IRC concerning exposure of
multiple named methods for the "other variants" -- ceiling,
floor and truncating division, in particular. We may need to
expose all 3, 

  

There are at least 6 different meanings of integer "divide". The
IEEE-754 spec has 5 rounding modes, each of which maps directly to
an integer div/mod rule:

  Truncate (round to zero: C-style, "%", "/" (integers only for
"/"))
  Floor (round to -inf: The proposal for "mod" and "div")
  Ceil (round to +inf)
  Round to nearest, ties to even (default floating point
rounding mode) (modulo is in the range [ -|d|/2 .. |d|/2])
  Round to nearest, ties away from zero (grade-school rounding)
  (not IEEE): Euclidean division (% is always positive - see [1])


Plus there's floating point division, which is fundamentally
different from integer division. Floating point division sets q =
D/d so that D = q*d ("modulo" part of the division equation is
zero). It's very different -- but all the integer modes still make
sense for floats, since floats can represent integers. 

I don't think it's a good idea to expose six (or seven) division
operators (though maybe they should all be in a library somewhere).
Truncate and floor are - by far - the most common integer modes, and
cover the normal programming use cases. 


  

  and it
might be the case that calling any of them 'quot' is just
misleading; it's not clear to me yet whether there's a
consistent method _name_ to assign '/' to (floating point
divide seems to do the opposite of integer divide on chips
that have both).
  

  

I don't think it is possible to come up with one short word that
means both "rounded floating-point division" and "truncating integer
division". Maybe just call it "div_sign_op" and have it call "quot"
for integers and "float_div" for floats?

  

  

But I don't think it's wise to map % to 'mod' if we're
exposing both 'mod' and 'rem'. That's a separate issue and
one with (I think) a simpler answer for us.
  

  

Agreed. "%" and "/" should satisfy the division rule [D = d*(D/d) +
(D%d)], which requires "%" to map to rem if "/" truncates. 


Being "close-to-the-metal" seems to be very important. In the case
of division, it's not as clear-cut as "what does Intel's 'idiv'
implement". "idiv" is only used for division when the denominator is
not a compile-time constant. When "idiv" is used, T-division
(C-style) is closer to the metal. (Note: no hardware divide on ARM,
so no difference there.)
But when the denominator is known at compile-time, it's transformed
into a multiply (or a bitwise-and for power-of-two denominator). In
both the "multiply" and "bitwise-and" algorithms, F-division is
closer to the metal (fewer instructions needed, on average). In any
case where the denominator is a constant, F-division is the same
speed or faster (and that's a big percent of divides in a lot of
code - especially performance-conscious code). 

[1]:
https://biblio.ugent.be/input/download?func=downloadFilerecordOId=314490fileOId=452146   
or

Re: [rust-dev] Division and modulo for signed numbers

2013-04-23 Thread Erik S

On 4/23/2013 9:02 AM, Patrick Walton wrote:
 On 4/23/13 7:48 AM, sw...@earthling.net wrote:
 Performance should be about the same when using F-division:
   * Performance will go up for division by constant powers of two.
   * Performance will stay the same for division by compile-time
 constants, since these are transformed by the compiler into
 multiplies. (I actually think performance will go up slightly in this
 case, but it's been a while since I looked at the algorithm.)
   * Performance on ARM will stay the same for divides by variables
 (not known at compile-time), since ARM does not have a hardware divider.
   * Performance on x86/x64 for divides by variables will go down
 slightly, since Intel's idiv instruction implements F-division.

 So one already very slow operation (x86 idiv) gets slightly slower,
 one fast operation (divide by power-of-two) gets quite a bit faster.
 It probably nets out near zero.

 I worry quite a bit about that last one. Rust language semantics
 strive to mirror the CPU instructions as closely as possible. This is
 why, for example, we were forced to make `` respect NaN, unlike
 Haskell--if we didn't, we couldn't use the hardware floating point
 comparison instructions.

 I'm also nervous about C interoperability.

 Including F-division as a library function sounds fine to me
 though--macros or dot notation may be able to sweeten the syntax.

 Patrick

 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev

Patrick,
I would agree with you if it weren't for the cases where F-division
performs *better*. Division by a constant power-of-two is pretty common,
and is much faster in F-division.

I don't think correctness should be sacrificed for a slight performance
improvement in one case on one supported architecture. I've had real
bugs in my C code caused by incorrectly casting (or forgetting to cast)
to unsigned before a % operation. T-division causes *real* bugs.

I'm willing to spend some time implementing F-division, if I can get
some buy-in that the patch would be accepted.

Erik
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Division and modulo for signed numbers

2013-04-23 Thread Erik S
Thanks Graydon for the detailed reply to a newbie suggestion. It looks
like I'm a little too late, this ship has already sailed. You're right
that it's a topic reasonable people can disagree on. Adding Lint
warnings seems like a poor workaround, but maybe the reduced confusion
from C developers will outweigh the bugs caused. Or maybe all
right-thinking people will agree to use the F-division function calls,
and / and % will be unknown to Rust developers  :-)

I just looked over the Numeric traits bikeshed and pull 5990, and have a
few comments.
 ( https://github.com/mozilla/rust/wiki/Bikeshed-Numeric-Traits and
https://github.com/mozilla/rust/pull/5990 )

The floating point quot operator is now misnamed. It returns D/d,
which is a floating point divide, not a quotient.
(src/libcore/num/f32.rs line 323)

I would suggest having floating point quot and rem return proper
quotient and remainder (i.e. D.quot(d) has the same value for int and
float, if the input/result is representable).

Then the floating-point / operator needs to be mapped to a something
other than quot (maybe div_float?). The % operator can be removed
on floating point numbers. When a floating-point remainder is needed,
you would have to call rem() explicitly. The numeric traits do not
appear to require a % operator (which is probably a good thing,
because it is hard to define for complex numbers).


Finally some code review comments (possible already fixed, I didn't have
time to check the tip - sorry)

modulo replaced with rem inappropriately in a comment
src/libstd/base64.rs line 118


Divide by zero error string became Quotient of zero
src/libstd/num/rational.rs line 54
src/librustc/middle/trans/base.rs line 788, 790
src/test/compile-fail/eval-enum.rs line 2,3


Regards,
Erik


On 4/23/2013 11:46 AM, Graydon Hoare wrote:
 On 23/04/2013 8:53 AM, Diggory Hardy wrote:

 I suspect (please correct me if I'm wrong) that if it wasn't for C
 and x86
 compatibility then most people would fall into two categories: don't
 know/don't care, and prefer F-division. It's one of those little
 things like
 tau vs. pi which would have been less confusing if we'd started off
 on the
 other foot to start with.

 And IP addresses would have been 64 or 128bit from the start, there
 would only be one endianness,  and so forth ... yes, sure. But we
 don't cast off the weight of the past so easily, and I do not think
 this is something it's wise to fiddle with.

 A very widely-applied design choice in rust is that the basic types
 are machine-sized and the arithmetic operations on them are (as close
 as reasonable to) machine operations. The machine operation is remainder.

 Moreover, it's not just C and x86. This same choice is taken (more
 or less) by PowerPC, LLVM, C++, C#, Java, D, Go, JS, Scala, Ocaml,
 etc. etc.

 The path we've taken here is to admit _two_ operation-pairs, div/mod
 and quot/rem. This path is taken by several languages and specs
 (Scheme, Common Lisp, Ruby, Smalltalk, SML, Prolog, Haskell, Ada, and
 ISO 10967 and IEEE 754). The work for this landed last week:

 https://github.com/mozilla/rust/pull/5990
 https://github.com/mozilla/rust/pull/6013
 https://github.com/mozilla/rust/issues/4565
 https://github.com/mozilla/rust/issues/4917

 (Phew! This must really be the week for integer division!)

 The only remaining thing to struggle with is which of the two
 operation-pairs to assign the / and % symbols to, in the
 operator-overloading sense. For this, we've gone with quot/rem, as in
 the other languages above, and in keeping with the design preference
 above. You have to call .mod() or .div() to get the other operators.

 It does mean there's a bit of a footgun surrounding the symbols / and
 % specifically, on signed integer types. I would not be at all opposed
 to adding a lint flag to calls-to-/-and-%-on-signed-integer-types,
 such that you could trap them all. As with many things here, the
 design space includes a variety of (sensible) preferences.

 -Graydon

 (Please correct me if I've swapped which of the two meanings we've
 actually assigned; this is one of those issues like double-negation
 and off-by-one indexing where I get things backwards no matter how
 much energy I spend on making sure I get it right.)

 ___
 Rust-dev mailing list
 Rust-dev@mozilla.org
 https://mail.mozilla.org/listinfo/rust-dev


___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev