sum, overflow := a + b
difference, underflow := a - b
product, high_product := a * b
quotient, remainder := a / b
Oh, how beautiful these would be! It would be poetry...
Your program must rely,
on these four arithmetic friends;
Each, two answers supply,
on which all correctness depends.
--
Michael T. Jones | Chief Technology Advocate | m...@google.com | +1
650-335-5765
LGFM
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
This could be handled like a type assertion, or a map lookup:
v, ok := a[x] // ok is false if a has no element with key x
r, ok := i.(io.Reader) // ok is false if i doesn't implement io.Reader
Without the multi-assignment, v is assigned a zero value (as it is
above) and the assignment to r causes a panic.
--
matt kane's brain
http://hydrogenproject.com
> On Fri, Mar 23, 2012 at 22:13, Hotei <hote...@gmail.com> wrote:
>> The problem is that _most_ of the time I don't want/need to write:
>>
>> sum, _ := a + b
>
> This could be handled like a type assertion, or a map lookup:
-1. I'm already not a fan of the existing cases where this happens (particularly with channels).
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.
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
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))
+1
// two-valuedfunc Foo(w, x float64) { ... }Foo(y/z)
> Wouldn't this proposal add another case of inconsistency?
Yes, it would -- don't do it!
> With the proposal, there would be some cases where you can ignore
> multiple return values, and some where you can't. Every additional
> case of inconsistency makes the language harder to learn and
> understand. One thing I really like in Go is the low number of
> exceptions you need to know or understand.
I began looking at Go a couple of weeks ago. I'm sorry to say it, but
the first impression was that Go is a terribly *inconsistent* language.
For a newly designed language, there is too many "magic" things that the
built-in operators and functions can do that user-defined functions
cannot do. I'm thinking of
value, ok := some_map[key] vs value := some_map[key]
It might have looked cool and you even gave it a name (the "comma ok"
idiom). But I cannot do the same for a normal function:
foo, err := os.Open("foo.txt")
foo := os.Open("foo.txt")
The magic "make" and "new" functions also have special powers that we
cannot use. First, they take a type as argument -- that's already iffy.
Second, they take a variable number of arguments without being variadic.
The "range" operator/function/clause is also weird in the same way that
the "comma ok" idiom is weird: you can ignore a second return value
without using _. You cannot ignore the first, so you have to write
for _, value := range some_map { ... }
Would it not have been much more consistent to always require two
variables? Even better: give maps keys() and values() methods (that
return slices) that you can iterate over. Abstract that into an
interface and you can suddenly iterate over user-defined types.
Strings also feels inconsistent to me. They are very much like immutable
byte slices, except that you iterate over UTF-8 decoded code points?!
That's very nice and practical, but now you've implicitly defined the
format of strings to be UTF-8. Not quite, though, since the range
operator will produce 0xFFFD if it encounters invalid UTF-8 bytes. How
can such a string even be produced?
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.
--
Martin Geisler
Mercurial links: http://mercurial.ch/
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.
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.
There are no other major things that will surprise you when you delve
in deeper, the way lazy evaluation might in Haskell, or generators
might in Python. It's all out up front.
+1
Thanks.
+1 Yes, you're right.
+1
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.
Rémy.
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?
Rémy.
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?
+1
The easiest way to do it currently.
>> 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 :)
--
Martin Geisler
aragost Trifork
Professional Mercurial support
http://www.aragost.com/mercurial/
> 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.)
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.
--
=====================
http://jessta.id.au
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?
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.
> 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!
if "range" is so simple then why does python need "xrange"?
The dual value form only makes sense for a single operation. I have suggested it exclusively that way during the past year or more.
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.
q, r := n/d, n%d
q := n/dr := n%d
q, r := n/d
// assume a is positivena := n + aif na < n {// we overflowed}
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%dis probably worse thanq := n/dr := n%dandq, r := n/dreally 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 positivena := n + aif 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!
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).
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!
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
> A seperate operator set should be used if this where to be implemented. For
> instance:
>
> sum, overflow := a +% b
> difference, underflow := a -% b
> product, high_product := a *% b
> quotient, remainder := a /% b
>
> or something like that..
Why don't we just write some ordinary functions?
Ian
Ian
> Den 02:58 28. mars 2012 skrev Ian Lance Taylor <ia...@google.com> følgende:
>
>> Sindre Myren <smy...@gmail.com> writes:
>>
>> > A seperate operator set should be used if this where to be implemented.
>> For
>> > instance:
>> >
>> > sum, overflow := a +% b
>> > difference, underflow := a -% b
>> > product, high_product := a *% b
>> > quotient, remainder := a /% b
>> >
>> > or something like that..
>>
>> Why don't we just write some ordinary functions?
>>
>>
> Like this?
>
> sum, overflow := AddWithOverflow(a, b)
> difference, underflow := SubtractWithUnderFlow(a , b)
> product, high_product := MultiplicationWithHighProduct(a, b)
> quotient, remainder := DivisionWithRemainder(a, b)
Yes.
> One would loose the "one operation" on the CPU point, which seamed to be of
> interest in this discussion, would one not?
We can write them in assembler.
Ian
I yield that it will be a function, which anyone can easily write,
it's just sad that the bit/word/value to be computed after the
function call is already there in the registers!
--
Sindre Myren <smy...@gmail.com> writes:Yes.
> Den 02:58 28. mars 2012 skrev Ian Lance Taylor <ia...@google.com> følgende:
>
>> Sindre Myren <smy...@gmail.com> writes:
>>
>> > A seperate operator set should be used if this where to be implemented.
>> For
>> > instance:
>> >
>> > sum, overflow := a +% b
>> > difference, underflow := a -% b
>> > product, high_product := a *% b
>> > quotient, remainder := a /% b
>> >
>> > or something like that..
>>
>> Why don't we just write some ordinary functions?
>>
>>
> Like this?
>
> sum, overflow := AddWithOverflow(a, b)
> difference, underflow := SubtractWithUnderFlow(a , b)
> product, high_product := MultiplicationWithHighProduct(a, b)
> quotient, remainder := DivisionWithRemainder(a, b)
On Tue, Mar 27, 2012 at 6:23 PM, Ian Lance Taylor <ia...@google.com> wrote:Sindre Myren <smy...@gmail.com> writes:Yes.
> Den 02:58 28. mars 2012 skrev Ian Lance Taylor <ia...@google.com> følgende:
>
>> Sindre Myren <smy...@gmail.com> writes:
>>
>> > A seperate operator set should be used if this where to be implemented.
>> For
>> > instance:
>> >
>> > sum, overflow := a +% b
>> > difference, underflow := a -% b
>> > product, high_product := a *% b
>> > quotient, remainder := a /% b
>> >
>> > or something like that..
>>
>> Why don't we just write some ordinary functions?
>>
>>
> Like this?
>
> sum, overflow := AddWithOverflow(a, b)
> difference, underflow := SubtractWithUnderFlow(a , b)
> product, high_product := MultiplicationWithHighProduct(a, b)
> quotient, remainder := DivisionWithRemainder(a, b)
Unfortunately, this requires one function per operation (4) per signedness (2) per bit width (4), so 32 different functions, unless I'm missing something. Otherwise you miss out entirely on the point of the second operands.
On Wed, Mar 28, 2012 at 11:56 AM, Kyle Lemons <kev...@google.com> wrote:On Tue, Mar 27, 2012 at 6:23 PM, Ian Lance Taylor <ia...@google.com> wrote:Sindre Myren <smy...@gmail.com> writes:Yes.
> Den 02:58 28. mars 2012 skrev Ian Lance Taylor <ia...@google.com> følgende:
>
>> Sindre Myren <smy...@gmail.com> writes:
>>
>> > A seperate operator set should be used if this where to be implemented.
>> For
>> > instance:
>> >
>> > sum, overflow := a +% b
>> > difference, underflow := a -% b
>> > product, high_product := a *% b
>> > quotient, remainder := a /% b
>> >
>> > or something like that..
>>
>> Why don't we just write some ordinary functions?
>>
>>
> Like this?
>
> sum, overflow := AddWithOverflow(a, b)
> difference, underflow := SubtractWithUnderFlow(a , b)
> product, high_product := MultiplicationWithHighProduct(a, b)
> quotient, remainder := DivisionWithRemainder(a, b)
Unfortunately, this requires one function per operation (4) per signedness (2) per bit width (4), so 32 different functions, unless I'm missing something. Otherwise you miss out entirely on the point of the second operands.Oh, I forgot about float32 and float64 and possibly complex64 and complex128 (I'm not sure if they make sense).