Well since I guess this was a proposal of sorts let me modify and
clarify somewhat.
Quick summary:
1. Add a binary operator or function that returns both the quotient
and modulo.
I propose /% as an operator, otherwise math.Divmod(a, b int) (q, m
int)
2. Is there any reason to require we assign multiple values? Why not
simply allow us to ignore a second result rather than force us to use
`_'
I hadn't realized that a map reference didn't require the second
value to be assigned. It's a strange inconsistency, but I'd rather
that become the standard rather than the underscore. If I want to
ignore something, and the language allows me to ignore it, why should
I have to tell the compiler "I'm ignoring that"
I should also point out that in LISP the TRUNCATE function is what
returns Quotient and Modulo. The / function in Lisp is a generic, if
you call it with two integers it returns a fraction.
> Well since I guess this was a proposal of sorts let me modify and > clarify somewhat.
> Quick summary:
> 1. Add a binary operator or function that returns both the quotient > and modulo. > I propose /% as an operator, otherwise math.Divmod(a, b int) (q, m > int)
> 2. Is there any reason to require we assign multiple values? Why not > simply allow us to ignore a second result rather than force us to use > `_'
> I hadn't realized that a map reference didn't require the second > value to be assigned. It's a strange inconsistency, but I'd rather > that become the standard rather than the underscore. If I want to > ignore something, and the language allows me to ignore it, why should > I have to tell the compiler "I'm ignoring that"
> I should also point out that in LISP the TRUNCATE function is what > returns Quotient and Modulo. The / function in Lisp is a generic, if > you call it with two integers it returns a fraction.
Le 25 mars 2012 14:23, ajventi <ajve...@gmail.com> a écrit :
> Well since I guess this was a proposal of sorts let me modify and > clarify somewhat.
> Quick summary:
> 1. Add a binary operator or function that returns both the quotient > and modulo. > I propose /% as an operator, otherwise math.Divmod(a, b int) (q, m > int)
In what kind of programs do you expect to use that?
> 2. Is there any reason to require we assign multiple values? Why not > simply allow us to ignore a second result rather than force us to use > `_'
I'm not sure what is the use for a new magic operator if you are going to ignore return values.
I use this kind of operation all of the time for getting I,j,k,....,m coordinates in an n-dimensional array that is stored in a one-dimensional array (or slice).
> 1. Add a binary operator or function that returns both the quotient
> and modulo.
> I propose /% as an operator, otherwise math.Divmod(a, b int) (q, m
> int)
> 2. Is there any reason to require we assign multiple values? Why not
> simply allow us to ignore a second result rather than force us to use
> `_'
What about this:
c, d := a + b, a /% b
c, d, r := a + b, a /% b
It seems to be a little confusing to me.
I think that it will be sufficient if the compiler specification will
guarantee that:
d, r := a / b, a % b
will be optimized on platforms that perform such operation using one
machine instruction.
Le 25 mars 2012 21:43, ajventi <ajve...@gmail.com> a écrit :
>> In what kind of programs do you expect to use that?
> Really? Have you ever wondered what sort of magic it takes to convert > an integer into a string?
Yes, I have. And there's already a package doing that. It can be optimized and expanded. My question is more about real world programs that would have a clear benefit out of "q, r := a /% b" vs. "q, r := a/b, a%b".
I just don't see an added value for a new operator from the discussion (as opposed to the detection of overflow, which I think would be valuable). I think that /% is not really readable, and I can't think of a symbol that looks readable. Also I don't think performance matters as a criterion to decide what a language should look like, except maybe, for the overall design, but not at that level of detail.
And about performance, I'd like to know if performance would be improved by adding that operator and mapping it to the corresponding instruction. Do you have benchmarks?
On Sunday, 25 March 2012 22:34:25 UTC+2, Rémy Oudompheng wrote:
> And about performance, I'd like to know if performance would be
> improved by adding that operator and mapping it to the corresponding
> instruction. Do you have benchmarks?
I'm not sure how you would benchmark that, short of
- writing a simple program where this proposal would simplify the code
- disassembling it
- rewriting the relevant parts of it in assembler by hand
> > 1. Add a binary operator or function that returns both the quotient > > and modulo. > > I propose /% as an operator, otherwise math.Divmod(a, b int) (q, m > > int)
> > 2. Is there any reason to require we assign multiple values? Why not > > simply allow us to ignore a second result rather than force us to use > > `_'
> What about this:
> c, d := a + b, a /% b > c, d, r := a + b, a /% b
> It seems to be a little confusing to me.
> I think that it will be sufficient if the compiler specification will > guarantee that:
> d, r := a / b, a % b
> will be optimized on platforms that perform such operation using one > machine instruction.
andrey mirtchovski <mirtchov...@gmail.com> writes: >> As a new user it feels inconsistent. Not broken and not something you >> cannot get used to, but the inconsistencies stand out.
> One of the nice things Go has got going for it, in my opinion: the > inconsistencies are in-your-face when you start using it, but they're > a relatively small number (you've pretty much enumerated them all, > leaving one or two gotchas having to do with closures or goroutines > that catch newcomers). It's a set that one can definitely keep track > of in their head and quickly get accustomed to if they write Go code > primarily.
Thanks, that is a another good point that I hadn't considered :)
John Asmuth <jasm...@gmail.com> writes: > On Saturday, March 24, 2012 3:16:31 PM UTC-4, Martin Geisler wrote:
>> This is just a brain-dump after playing with Go for some weeks. As a >> new user it feels inconsistent. Not broken and not something you >> cannot get used to, but the inconsistencies stand out.
> I believe it is not true that a language needs to be inconsistent. > "Fairness" adds no benefit to anyone who isn't trying to tinker with > and extend the language via userspace. It doesn't actually make it > easier to write real code.
That's an interesting point and I admit that I haven't thought of it like this before.
For me, the inconsistencies makes it (ever so slightly) harder to get a firm mental model for the language. I'm used to Python, and there's it's no mystery what 'range' is -- it's a function like any other. So
for i in range(10): ...
is easy: range(10) returns a generator that I can iterate over. An iterator is itself just an object that implements a ceratain interface. Since it's just a normal object, I can trivially do
seq = range(10) for i in seq: ...
and get the same result. With Go I cannot do
seq := range some_array
and then iterate over the array later -- range is "magic" somehow and I don't know what it "is". (Of course I know what it is, it's a syntax that can be used in a for-loop to iterate over certain types. But I somehow feel that this explanation is more opaque than in Python.)
On Mon, Mar 26, 2012 at 11:20 PM, Martin Geisler <m...@aragost.com> wrote: > I'm used to Python, and there's it's > no mystery what 'range' is -- it's a function like any other. So
> for i in range(10): ...
But what is 'in'? 'in' is usually a boolean operator eg.
seq = range(10) i = 2 a = i in seq # a is True
But in a for loop 'in' magically also assigns to i and has a completely different behaviour.
i = 2 for i in [1,2,3,4,5,6]: print(i) i = 20
for some reason my Boolean expression is acting in a very strange way and the loop isn't break when i is no longer within the list.
> For me, the inconsistencies makes it (ever so slightly) harder to get a > firm mental model for the language. I'm used to Python, and there's it's > no mystery what 'range' is -- it's a function like any other. So
if "range" is so simple then why does python need "xrange"? what's the difference between them? why use one instead of the other? is range even thread-safe?
> if "range" is so simple then why does python need "xrange"? what's the
> difference between them? why use one instead of the other? is range
> even thread-safe?
"xrange" is the generator version of "range." It's useful particularly
when the collection you're iterating over is large in size. (xrange
makes sure only one element is in memory whereas range forces all
elements to occupy memory.)
At least, that's my understanding of the difference.
On Sat, Mar 24, 2012 at 8:32 AM, Michael Jones <m...@google.com> wrote: > BACKGROUND
> To clarify, I should not have used the terms overflow and underflow. I was > thinking "expose the hardware truth" and that's what the corresponding > values are usually called in CPUs, but in fact, at the logical, mathematics > level there is no such thing as over or under-flow. so 'carry' and 'borrow' > are better words.
> Adding two n-digit signed integers in any base may produce an n+1 digit > result. When this happens in real life (5+5 = 10) we consider it as > ordinary, when it happens in code (5+5 = 0) we also take no special action > and the program continues on with "0" and ignores the "overflow == carry of > 1 == lost sum equal to 10" situation. NOTE: This truncation of the high > digit happens in [asymptotically] 50% of same-sign additions. (2147450880 > of 4294967296 16-bit additions, or about 49.999237060546875%) The CPU does > not ignore these cases but high level languages do. It has always been a > concern of mine that otherwise careful language designers are blind to > this--as a child (10 years old/4th grade, writing in assembler) I learned > to treat overflow carefully.
> Now we have Go, with clean multiple value assignment. It could be used to > simplify the natural fact that fixed-precision basic integer arithmetic > operations always produce two results, just as it could be used in the > normal usage case where the programmer and program desire to hide from this > fact.
> sum := a + b > sum, carry := a + b // ",carry" optional, and ONLY in simple addend+augend > expression > sum, carry := a SpecialTwoValuedAdditionSymbol b > sum, carry := SpecialTwoValueAdditionFunction(a, b)
> difference := a - b > difference, borrow := a - b // ",borrow" optional, and ONLY in simple > minuend-subtrahend expression > difference, borrow := a SpecialTwoValuedSubtractionSymbol b > difference, borrow := SpecialTwoValuedSubtractionFunction(a, b)
> The carry and borrow will be zero if a and b are of different signs and > +/- 1 in the overflow case. The sign of the borrow could arguably be > positive or negative, I have an opinion but it does not matter what > convention is chosen (are you borrowing 1 x -(2^n) or are you borrowing -1 > x 2^n.)
> For multiplication the situation is the same in presentation but extremely > different in distribution. Multiplying two n-digit signed integers may > produce numbers with up to 2n digits in length. When this happens in real > life (10*10 = 100 or 99*99 = 9801) we see no adventure, just as in Go code > where 10*10 = 0 and 99*99 = 1 (substituting binary of course for this > decimal example) causes no panic and is business as usual. Where there is a > difference in character from addition is in how many of the possible > multiplications overflow. First, differing signs do not save you as they do > with addition. Let's consider an n-digit, base 10 multiplication table > (starting at 0) and count how many of the entries are >= 10^n and thus > would truncate. The answer is:
> 0..9 x 0..9: 58 of 100 = 58% > 0..99 x 0.99: 9328 of 10000 = 93.28% > 0..999 x 0.999: 990948 of 1000000 = 99.0948%
> For 16-bit binary multiplication the total is 4294099268 of 4294967296, > which means 99.97978964820504% of possible 16-bit x 16-bit multiplications > produce a non-zero upper 16-bits of product. (That is just 2 in 10,000 that > don't overflow, which may seem shocking but is consistent with the > asymptotic sense--half for addition and all for multiplication.) This is so > significant that every CPU has been a champ and handling this. Despite the > commonality of the upper-half "overflow" product and perfect handling of it > in CPUs, it is perfectly ignored in high-level languages. (Solutions are to > use bigger word sizes or floating point.) However, in Go with the natural > means for two results from one expression, we can have:
> product := a * b > product, upper := a * b // ",upper" optional, and ONLY in simple > multiplier*multiplicand expression > product, upper := a SpecialTwoValuedMultiplicationSymbol b > product, upper := SpecialTwoValueMultiplicationFunction(a, b)
> Division is the remaining basic integer operation, and we have the > mathematical quotient and remainder via two single purpose operators:
> quotient := a / b // truncating integer division > remainder := a % b // modulus operation == remainder of division operation
> This is much better than the above three cases because we are already > offered access to the secondary result by a secondary function. It is the > same concept as:
> sum := a + b > carry := a CarryFromAdd b
> or
> product := a * b > upper := a UpperProduct b
> and in all three cases we would like to mandate that the compiler produce > the two results from the single machine operation that is implied. Cleaner, > though, and more clearly one logical operation would be a single and > dual-result operations:
> quotient := a / b > quotient, remainder := a / b
> and maybe
> _,remainder = a / b // just an idea -- not arguing for this.
> How often is the remainder non-zero? Precisely when numerator and > denominator are relatively prime. There is depth in that question but a > simple tabulation suffices:
> 1..9 / 1..9: 58 of 81 relatively prime = 71.60493827160493% > 1..99 / 1..99: 9328 of 9801 relatively prime = 95.17396184062851% > 1.999 / 1.999: 990948 of 998001 relatively prime = 99.29328728127527%
> For 16-bit unsigned integers, the answer is that 4294099268 of 4294836225 > (99.98284085908304%) divisions have a non-zero remainder so we should be > grateful that we at least have the modulus operator even if it presently > takes two lines of code and replication of the numerator and denominator > expressions to compute a simple quotient and remainder. (Note that the > non-zero remainder case in division is more frequent than a non-zero upper > product in multiplication--loosely an "almost always" situation.)
> I would be proud if Go were the first systems language to make the reality > of addition, subtraction, multiplication, and division become first-class > elements of the language.
I've been thinking about this. As much as
quo, rem := dd / div
looks sexy, the following does not:
quo, rem := a*b / c*d (yes, it is deliberately incorrect)
For both clarity and distinction, I would slightly prefer the addition of builtin add(), mul(), sub(), and div() functions with either fixed or variadic returns.
>>> This is no different from the contextual awareness of map indexing.
>>> // single-valued >>> aVal := aMap[aKey]
>>> // two-valued >>> aVal, ok : = aMap[aKey]
>>> On Friday, March 23, 2012 11:21:14 PM UTC-4, Hotei wrote:
>>>> John, >>>> "They can simply rely on context" - is that saying they can deduce my >>>> intent? I find that hard to imagine even in the trivial case listed below.
>>>> On Friday, March 23, 2012 11:10:17 PM UTC-4, John Asmuth wrote:
>>>>> Built-ins don't suffer from the need to explicitly ignore values. They >>>>> can simply rely on context.
>>>>> On Friday, March 23, 2012 10:13:24 PM UTC-4, Hotei wrote:
>>>>>> The problem is that _most_ of the time I don't want/need to write:
>>>>>> sum, _ := a + b
>>>>>> and how to handle more complex formulae like:
>>>>>> result, err := math.Sqrt((a-b) * (a+b))
>>>>>> is err an overflow, underflow, high_product or a sqrt(neg) error?
>>>>>> Isn't that confusion a logical result of this proposal? My 2c .
>>>>>> On Friday, March 23, 2012 9:51:33 PM UTC-4, Mikael Gustavsson wrote:
>>>>>>> On Saturday, March 24, 2012 5:49:17 AM UTC+8, Michael Jones wrote:
>>>>>>>> I like the idea too. Though it tends to get rejected each time it is >>>>>>>> brought up. There are four in total:
>>>>>>>> sum, overflow := a + b >>>>>>>> difference, underflow := a - b >>>>>>>> product, high_product := a * b >>>>>>>> quotient, remainder := a / b
>>>>>>> That is seriously cool! >>>>>>> It's also in line with the Go philosophy of explicit error handling.
>>>>>>> But I doubt it's going to happen due to the overloading of return >>>>>>> types of the basic operators.
>>>> On Friday, March 23, 2012 11:10:17 PM UTC-4, John Asmuth wrote:
>>>>> Built-ins don't suffer from the need to explicitly ignore values. They >>>>> can simply rely on context.
>>>>> On Friday, March 23, 2012 10:13:24 PM UTC-4, Hotei wrote:
>>>>>> The problem is that _most_ of the time I don't want/need to write:
>>>>>> sum, _ := a + b
>>>>>> and how to handle more complex formulae like:
>>>>>> result, err := math.Sqrt((a-b) * (a+b))
>>>>>> is err an overflow, underflow, high_product or a sqrt(neg) error?
>>>>>> Isn't that confusion a logical result of this proposal? My 2c .
>>>>>> On Friday, March 23, 2012 9:51:33 PM UTC-4, Mikael Gustavsson wrote:
>>>>>>> On Saturday, March 24, 2012 5:49:17 AM UTC+8, Michael Jones wrote:
>>>>>>>> I like the idea too. Though it tends to get rejected each time it is >>>>>>>> brought up. There are four in total:
>>>>>>>> sum, overflow := a + b >>>>>>>> difference, underflow := a - b >>>>>>>> product, high_product := a * b >>>>>>>> quotient, remainder := a / b
>>>>>>> That is seriously cool! >>>>>>> It's also in
On Mon, Mar 26, 2012 at 2:19 PM, Kyle Lemons <kev...@google.com> wrote:
> quo, rem := a*b / c*d > (yes, it is deliberately incorrect)
Huh - I thought have thought that times would come before divide. I guess that only serves your point.
> For both clarity and distinction, I would slightly prefer the addition of > builtin add(), mul(), sub(), and div() functions with either fixed or > variadic returns.
On Mon, Mar 26, 2012 at 11:28 AM, John Asmuth <jasm...@gmail.com> wrote:
> On Mon, Mar 26, 2012 at 2:19 PM, Kyle Lemons <kev...@google.com> wrote:
>> quo, rem := a*b / c*d >> (yes, it is deliberately incorrect)
> Huh - I thought have thought that times would come before divide. I guess > that only serves your point.
>> For both clarity and distinction, I would slightly prefer the addition of >> builtin add(), mul(), sub(), and div() functions with either fixed or >> variadic returns.
> Maybe in a package, rather than built-in?
>> quo, rem := div(a*b, c*d)
-- Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 650-335-5765
Jesse McNelis <jes...@jessta.id.au> writes: > On Mon, Mar 26, 2012 at 11:20 PM, Martin Geisler <m...@aragost.com> wrote: >> I'm used to Python, and there's it's no mystery what 'range' is -- >> it's a function like any other. So
>> for i in range(10): ...
> But what is 'in'? 'in' is usually a boolean operator eg.
> seq = range(10) > i = 2 > a = i in seq > # a is True
> But in a for loop 'in' magically also assigns to i and has a > completely different behaviour.
Hmm... :-) I think the crucial point was the ":=" part for me. In Go you write
for v := range someArray { ... }
and in Python you write
for v in someSeq: ...
There's no assignment (=) in Python and "for <vars> in <something>" is the syntax. The equivalent in Go is "for <vars> := range <something>". The use of ":=" somehow looked weird to me.
> i = 2 > for i in [1,2,3,4,5,6]: > print(i) > i = 20
> for some reason my Boolean expression is acting in a very strange way > and the loop isn't break when i is no longer within the list.
Hmm... :-) I see "for ... in" as a single construct and never thought twice about that "in" is also a binary operator.
I get your point and I'll get used to the syntax. Thanks for the discussion!
On Mon, Mar 26, 2012 at 11:30 AM, Michael Jones <m...@google.com> wrote: > The dual value form only makes sense for a single operation. I have > suggested it exclusively that way during the past year or more.
Ah. I don't think I'd seen you mention that it wouldn't be available if there were more than a single operation, but that makes a lot of sense too.
> On Mon, Mar 26, 2012 at 11:28 AM, John Asmuth <jasm...@gmail.com> wrote:
>> On Mon, Mar 26, 2012 at 2:19 PM, Kyle Lemons <kev...@google.com> wrote:
>>> quo, rem := a*b / c*d >>> (yes, it is deliberately incorrect)
>> Huh - I thought have thought that times would come before divide. I guess >> that only serves your point.
>>> For both clarity and distinction, I would slightly prefer the addition >>> of builtin add(), mul(), sub(), and div() functions with either fixed or >>> variadic returns.
>> Maybe in a package, rather than built-in?
>>> quo, rem := div(a*b, c*d)
> -- > Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 > 650-335-5765
Sorry. It certainly causes the two obvious objections:
1. What a special case! The "comma,overflow" is optional only in simple, single expressions. 2. What a rare case! How many people ever check for overflow!
Both are true. I admit that. However, how else would one code these cases portably? The answer is like this (for division, if there were no mod):
//want q,r := n/d, where 'n' and 'd' are arbitrary expressions.
t1 := n t2 := d // ...check for zero divisor here, then... q := n/d r := n - q*d
As it happens, this division case is by far the fastest to compute compared to the others, and even here, compilers are not good. If you look at Go now, you'll see that...
q := n/10 r := n%10
is 15% or so slower than
q := n/10 r := n - (q << 3 + q)
even though q and r are right there in CPU registers waiting to be use directly. It is much worse for multiplicative overflow, where the only real solutions involve breaking each factor into a high and low part (in BASE bitsize/2) and evaluating (a*BASE+b)*(c*BASE+d) in stages, again, even though the high product is right there in CPU registers waiting to be used with a single register move or test.
Maybe a reasonable compromise would be special functions (one of my example approaches):
s,o := SpecialAdd(a, b) d,u := SpecialSubtract(a, b) l,h := SpecialMultiply(a, b) q,r := SpecialDivide(a, b)
Where the compiler agrees that whatever names are chosen are reserved and handled inline.
On Mon, Mar 26, 2012 at 11:37 AM, Kyle Lemons <kev...@google.com> wrote: > On Mon, Mar 26, 2012 at 11:30 AM, Michael Jones <m...@google.com> wrote:
>> The dual value form only makes sense for a single operation. I have >> suggested it exclusively that way during the past year or more.
> Ah. I don't think I'd seen you mention that it wouldn't be available if > there were more than a single operation, but that makes a lot of sense too.
>> On Mon, Mar 26, 2012 at 11:28 AM, John Asmuth <jasm...@gmail.com> wrote:
>>> On Mon, Mar 26, 2012 at 2:19 PM, Kyle Lemons <kev...@google.com> wrote:
>>>> quo, rem := a*b / c*d >>>> (yes, it is deliberately incorrect)
>>> Huh - I thought have thought that times would come before divide. I >>> guess that only serves your point.
>>>> For both clarity and distinction, I would slightly prefer the addition >>>> of builtin add(), mul(), sub(), and div() functions with either fixed or >>>> variadic returns.
>>> Maybe in a package, rather than built-in?
>>>> quo, rem := div(a*b, c*d)
>> -- >> Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 >> 650-335-5765
-- Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 650-335-5765
On Mar 26, 2012, at 2:32 PM, Martin Geisler <m...@aragost.com> wrote:
> Hmm... :-) I think the crucial point was the ":=" part for me. In Go you > write
> for v := range someArray { ... }
> and in Python you write
> for v in someSeq: ...
> There's no assignment (=) in Python and "for <vars> in <something>" is > the syntax. The equivalent in Go is "for <vars> := range <something>". > The use of ":=" somehow looked weird to me.
I guess the way to see it is that the `range` is loop syntax that controls the loop and retrieves different values from the following expression on each iteration, like `in`, except that you then have to assign these values to variables rather than having it automatically bound to the identifier to the left of the keyword. Having the `:=` or `=` in there gives you control over declaration, which is a useful feature.
This and `switch x := v.(type)` are examples of where there's a bit of a "huh, how does that syntax compose, exactly?" moment when learning it. It isn't the obvious design. However, it is syntactically unambiguous, and in an odd kind of way suggests its intent. So it works, even if it seems odd.
I overall agree with Michael. I have found that expression is also much more difficult than concept, and expression is what the lexer and parser are all about.
I frequently need both the quotient and remainder and I am always annoyed that I have to repeat the operation twice.
q, r := n/d, n%d
is probably worse than
q := n/d r := n%d
and
q, r := n/d
really feels the most natural to me as a human.
I also have, not quite as frequently, had to check for carry, but it is always a special case:
// assume a is positive na := n + a if na < n { // we overflowed
}
Note the assume comment. For multiplication I simply give up and if possible use double the bit width (and hope that 64 bits is always enough).
To me it seems Michael is often working with real mathematics, unlike OS guys like me who think floating point is something for users :-) But even so, I see good reason to not throw away so much of what the CPU does for us. It is not as useless as nearly all modern languages make it appear.
For me the WHAT is "return us more complete results from CPU arithmetic operations" and I will leave the HOW up to the Go designers. The have done a good job thus far!
On Mon, Mar 26, 2012 at 11:56 AM, Michael Jones <m...@google.com> wrote: > Sorry. It certainly causes the two obvious objections:
> 1. What a special case! The "comma,overflow" is optional only in simple, > single expressions. > 2. What a rare case! How many people ever check for overflow!
> Both are true. I admit that. However, how else would one code these cases > portably? The answer is like this (for division, if there were no mod):
> //want q,r := n/d, where 'n' and 'd' are arbitrary expressions.
> t1 := n > t2 := d > // ...check for zero divisor here, then... > q := n/d > r := n - q*d
> As it happens, this division case is by far the fastest to compute > compared to the others, and even here, compilers are not good. If you look > at Go now, you'll see that...
> q := n/10 > r := n%10
> is 15% or so slower than
> q := n/10 > r := n - (q << 3 + q)
> even though q and r are right there in CPU registers waiting to be use > directly. It is much worse for multiplicative overflow, where the only real > solutions involve breaking each factor into a high and low part (in BASE > bitsize/2) and evaluating (a*BASE+b)*(c*BASE+d) in stages, again, even > though the high product is right there in CPU registers waiting to be used > with a single register move or test.
> Maybe a reasonable compromise would be special functions (one of my > example approaches):
> s,o := SpecialAdd(a, b) > d,u := SpecialSubtract(a, b) > l,h := SpecialMultiply(a, b) > q,r := SpecialDivide(a, b)
> Where the compiler agrees that whatever names are chosen are reserved and > handled inline.
> On Mon, Mar 26, 2012 at 11:37 AM, Kyle Lemons <kev...@google.com> wrote:
>> On Mon, Mar 26, 2012 at 11:30 AM, Michael Jones <m...@google.com> wrote:
>>> The dual value form only makes sense for a single operation. I have >>> suggested it exclusively that way during the past year or more.
>> Ah. I don't think I'd seen you mention that it wouldn't be available if >> there were more than a single operation, but that makes a lot of sense too.
>>> On Mon, Mar 26, 2012 at 11:28 AM, John Asmuth <jasm...@gmail.com> wrote:
>>>> On Mon, Mar 26, 2012 at 2:19 PM, Kyle Lemons <kev...@google.com> wrote:
>>>>> quo, rem := a*b / c*d >>>>> (yes, it is deliberately incorrect)
>>>> Huh - I thought have thought that times would come before divide. I >>>> guess that only serves your point.
>>>>> For both clarity and distinction, I would slightly prefer the addition >>>>> of builtin add(), mul(), sub(), and div() functions with either fixed or >>>>> variadic returns.
>>>> Maybe in a package, rather than built-in?
>>>>> quo, rem := div(a*b, c*d)
>>> -- >>> Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 >>> 650-335-5765
> -- > Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 > 650-335-5765
On Mon, Mar 26, 2012 at 12:59 PM, Paul Borman <bor...@google.com> wrote: > I overall agree with Michael. I have found that expression is also much > more difficult than concept, and expression is what the lexer and parser > are all about.
> I frequently need both the quotient and remainder and I am always annoyed > that I have to repeat the operation twice.
> q, r := n/d, n%d
> is probably worse than
> q := n/d > r := n%d
> and
> q, r := n/d
> really feels the most natural to me as a human.
> I also have, not quite as frequently, had to check for carry, but it is > always a special case:
> // assume a is positive > na := n + a > if na < n { > // we overflowed > }
> Note the assume comment. For multiplication I simply give up and if > possible use double the bit width (and hope that 64 bits is always enough).
> To me it seems Michael is often working with real mathematics, unlike OS > guys like me who think floating point is something for users :-) But even > so, I see good reason to not throw away so much of what the CPU does for > us. It is not as useless as nearly all modern languages make it appear.
> For me the WHAT is "return us more complete results from CPU arithmetic > operations" and I will leave the HOW up to the Go designers. The have done > a good job thus far!
+1
I suspect that, if given the ability, many more programmers will find that they've always wanted the feature but never known to ask for it.
> On Mon, Mar 26, 2012 at 11:56 AM, Michael Jones <m...@google.com> wrote:
>> Sorry. It certainly causes the two obvious objections:
>> 1. What a special case! The "comma,overflow" is optional only in simple, >> single expressions. >> 2. What a rare case! How many people ever check for overflow!
>> Both are true. I admit that. However, how else would one code these cases >> portably? The answer is like this (for division, if there were no mod):
>> //want q,r := n/d, where 'n' and 'd' are arbitrary expressions.
>> t1 := n >> t2 := d >> // ...check for zero divisor here, then... >> q := n/d >> r := n - q*d
>> As it happens, this division case is by far the fastest to compute >> compared to the others, and even here, compilers are not good. If you look >> at Go now, you'll see that...
>> q := n/10 >> r := n%10
>> is 15% or so slower than
>> q := n/10 >> r := n - (q << 3 + q)
>> even though q and r are right there in CPU registers waiting to be use >> directly. It is much worse for multiplicative overflow, where the only real >> solutions involve breaking each factor into a high and low part (in BASE >> bitsize/2) and evaluating (a*BASE+b)*(c*BASE+d) in stages, again, even >> though the high product is right there in CPU registers waiting to be used >> with a single register move or test.
>> Maybe a reasonable compromise would be special functions (one of my >> example approaches):
>> s,o := SpecialAdd(a, b) >> d,u := SpecialSubtract(a, b) >> l,h := SpecialMultiply(a, b) >> q,r := SpecialDivide(a, b)
>> Where the compiler agrees that whatever names are chosen are reserved and >> handled inline.
>> On Mon, Mar 26, 2012 at 11:37 AM, Kyle Lemons <kev...@google.com> wrote:
>>> On Mon, Mar 26, 2012 at 11:30 AM, Michael Jones <m...@google.com> wrote:
>>>> The dual value form only makes sense for a single operation. I have >>>> suggested it exclusively that way during the past year or more.
>>> Ah. I don't think I'd seen you mention that it wouldn't be available if >>> there were more than a single operation, but that makes a lot of sense too.
>>>> On Mon, Mar 26, 2012 at 11:28 AM, John Asmuth <jasm...@gmail.com>wrote:
>>>>> On Mon, Mar 26, 2012 at 2:19 PM, Kyle Lemons <kev...@google.com>wrote:
>>>>>> quo, rem := a*b / c*d >>>>>> (yes, it is deliberately incorrect)
>>>>> Huh - I thought have thought that times would come before divide. I >>>>> guess that only serves your point.
>>>>>> For both clarity and distinction, I would slightly prefer the >>>>>> addition of builtin add(), mul(), sub(), and div() functions with either >>>>>> fixed or variadic returns.
>>>>> Maybe in a package, rather than built-in?
>>>>>> quo, rem := div(a*b, c*d)
>>>> -- >>>> Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 >>>> 650-335-5765
>> -- >> Michael T. Jones | Chief Technology Advocate | m...@google.com | +1 >> 650-335-5765
andrey mirtchovski <mirtchov...@gmail.com> writes: >> For me, the inconsistencies makes it (ever so slightly) harder to get >> a firm mental model for the language. I'm used to Python, and there's >> it's no mystery what 'range' is -- it's a function like any other. So
> if "range" is so simple then why does python need "xrange"? what's the > difference between them? why use one instead of the other? is range > even thread-safe?
It doesn't really "need" it -- xrange is just there in case you're happy with an generator instead of a list. As you probably know, Python 3 only has xrange (and it has been renamed to range).