How multiply time.Duration by an integer?

11,451 views
Skip to first unread message

RickyS

unread,
Jun 19, 2013, 9:22:44 AM6/19/13
to golan...@googlegroups.com
I've calculated an interval as a time.Duration.  I want to print out a Duration that is 100 (for example) times as long?

The obvious expression gets a syntax error:
 invalid operation: maxOutstanding * runTime (mismatched types int and time.Duration)
 
Using go 1.1.1

   Thanks,
   Ricky

minux

unread,
Jun 19, 2013, 9:24:12 AM6/19/13
to RickyS, golan...@googlegroups.com
On Wed, Jun 19, 2013 at 9:22 PM, RickyS <rickys...@gmail.com> wrote:
> I've calculated an interval as a time.Duration. I want to print out a
> Duration that is 100 (for example) times as long?
>
> The obvious expression gets a syntax error:
> invalid operation: maxOutstanding * runTime (mismatched types int and
> time.Duration)
just convert the integer to time.Duration:
time.Duration(maxOutstanding) * runTime

chris dollin

unread,
Jun 19, 2013, 9:35:39 AM6/19/13
to minux, RickyS, golang-nuts
I'd feel dimensionally suspect multiplying a Duration by a Duration
and getting a Duration back.

time.Duration(maxOutstanding * int(runTime)) would make me feel
dimensionally satisfied at the cost of an extra cast.

How do others feel about this?

Chris

PS "invalid operation" isn't a syntax error, at least in the way I think
of syntax errors: `maxOutstanding * runTime` is a perfectly
syntactic expression that happens, by virtue of certain properties
of the identifiers in it, to be disallowed.

AgainChris

--
Chris "allusive" Dollin

minux

unread,
Jun 19, 2013, 9:42:37 AM6/19/13
to chris dollin, RickyS, golang-nuts
On Wed, Jun 19, 2013 at 9:35 PM, chris dollin <ehog....@googlemail.com> wrote:
> On 19 June 2013 14:24, minux <minu...@gmail.com> wrote:
>> On Wed, Jun 19, 2013 at 9:22 PM, RickyS <rickys...@gmail.com> wrote:
>> > I've calculated an interval as a time.Duration. I want to print out a
>> > Duration that is 100 (for example) times as long?
>> >
>> > The obvious expression gets a syntax error:
>> > invalid operation: maxOutstanding * runTime (mismatched types int and
>> > time.Duration)
>> just convert the integer to time.Duration:
>> time.Duration(maxOutstanding) * runTime
>
> I'd feel dimensionally suspect multiplying a Duration by a Duration
> and getting a Duration back.
>
> time.Duration(maxOutstanding * int(runTime)) would make me feel
> dimensionally satisfied at the cost of an extra cast.
nit pick: one should use int64 for durations in case int is 32-bit.

i don't feel too strong about this issue, and i think both solution is
acceptable to me.
and i think the performance should be effectively the same (if use
int64 instead of int).

Ian Lance Taylor

unread,
Jun 19, 2013, 9:55:38 AM6/19/13
to chris dollin, minux, RickyS, golang-nuts
On Wed, Jun 19, 2013 at 6:35 AM, chris dollin <ehog....@googlemail.com> wrote:
>
> I'd feel dimensionally suspect multiplying a Duration by a Duration
> and getting a Duration back.

Yeah, there is no way to express this sort of dimensional analysis in Go.

> time.Duration(maxOutstanding * int(runTime)) would make me feel
> dimensionally satisfied at the cost of an extra cast.

That is fine if you find it easier to read. The generated code will
most likely be the same. Note that you probably want int64 rather
than int.

> PS "invalid operation" isn't a syntax error, at least in the way I think
> of syntax errors: `maxOutstanding * runTime` is a perfectly
> syntactic expression that happens, by virtue of certain properties
> of the identifiers in it, to be disallowed.

Agreed, but I think it was you who said it was a syntax error. The
compiler only said it was an invalid operation, which it is.

Ian

chris dollin

unread,
Jun 19, 2013, 9:58:10 AM6/19/13
to Ian Lance Taylor, minux, RickyS, golang-nuts
--
Chris "allusive" Dollin

chris dollin

unread,
Jun 19, 2013, 10:00:50 AM6/19/13
to Ian Lance Taylor, minux, RickyS, golang-nuts
OOPS sorry for the previous message ... finger-fumble.

On 19 June 2013 14:55, Ian Lance Taylor <ia...@golang.org> wrote:
 
That is fine if you find it easier to read.  The generated code will
most likely be the same.  Note that you probably want int64 rather
than int.

I used int because the OP (RickyS) had used int.
 
> PS "invalid operation" isn't a syntax error, at least in the way I think
> of syntax errors: `maxOutstanding * runTime` is a perfectly
> syntactic expression that happens, by virtue of certain properties
> of the identifiers in it, to be disallowed.

Agreed, but I think it was you who said it was a syntax error.  The
compiler only said it was an invalid operation, which it is.

RickyS called it a syntax error.

Chris

--
Chris "allusive" Dollin

RickyS

unread,
Jun 19, 2013, 11:08:07 AM6/19/13
to golan...@googlegroups.com, Ian Lance Taylor, minux, RickyS, ehog....@googlemail.com
  1. So what's the solution? Casting? I think I can work that out.
  2. The compiler message included the phrase 'mismatched types', which sounds like a syntax error to me.  Conceptually, I disagree: I think it should be allowed.
  3. We can imagine a physics package that allows for time-squared to allow coding, as an example, Galileo's Law of Fall, which involves the square of an elapsed time (the square of a Duration).
  4. The time package has an Add(), I guess I could put that in a loop, add the appropriate number of Durations to a Time, and then subtract out the original Time.  It hurts even to think about this.

On Wednesday, June 19, 2013 5:00:50 PM UTC+3, chris dollin wrote:
 ...
 

Ian Lance Taylor

unread,
Jun 19, 2013, 11:23:24 AM6/19/13
to RickyS, golan...@googlegroups.com, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 8:08 AM, RickyS <rickys...@gmail.com> wrote:
> The compiler message included the phrase 'mismatched types', which sounds
> like a syntax error to me.

I guess we just disagree on terminology. I would call that a semantic
error, not a syntax error.

> Conceptually, I disagree: I think it should be
> allowed.

http://golang.org/doc/faq#conversions

Ian

chris dollin

unread,
Jun 19, 2013, 11:50:55 AM6/19/13
to RickyS, golang-nuts, Ian Lance Taylor, minux
On 19 June 2013 16:08, RickyS <rickys...@gmail.com> wrote:
  1. So what's the solution? Casting? I think I can work that out.
Conversion, rather than casting, but yes.
  1. The compiler message included the phrase 'mismatched types', which sounds like a syntax error to me.  Conceptually, I disagree: I think it should be allowed.
Syntax [IMAO] is about structure, how tokens can be combined to
make program texts. There wasn't a problem with your token combinations;
`a * b` is a structurally legal expression. The problem with your
multiplication is that the types bound to the identifiers don't conform
to the type rules of the language.

The type rules aren't rules about token sequences.

It's /possible/ to mash type rules into the same notation as token
rules -- witness, for example, Algol 68 -- but that's not the road
usually taken, for the usual sorts of decoupling reasons. Distinguishing
token rules from type (and other interpretation) rules is pragmatically
useful. 
  1. We can imagine a physics package that allows for time-squared to allow coding, as an example, Galileo's Law of Fall, which involves the square of an elapsed time (the square of a Duration).

Oh, sure, but Go's types aren't types that would help with that.
 
  1. The time package has an Add(), I guess I could put that in a loop, add the appropriate number of Durations to a Time, and then subtract out the original Time.  It hurts even to think about this.
Multiplication works for this, so long as you account for the types.

RickyS

unread,
Jun 19, 2013, 3:43:34 PM6/19/13
to golan...@googlegroups.com, RickyS, Ian Lance Taylor, minux, ehog....@googlemail.com
It depends on whether the integer is const or not.
This program works as expected:
package main
import ("fmt"; "time"; "reflect")
func main () {
  const m = 10
  fmt.Printf("TypeOf(m) is %s\n", reflect.TypeOf(m).Name())
  waiter := time.Duration(3600000000)
  bigwait := m * waiter
  fmt.Printf("waiter is %v, bigwait %v\n", waiter, bigwait)
}
The output is:
TypeOf(m) is int
waiter is 3.6s, bigwait 36s

But change the 'const m' to a 'var m' and the old error message returns:
invalid operation: m * waiter (mismatched types int and time.Duration)
NOTE:  The const is an int according to reflection, and the var is an int according to the error message, so the problem isn't about the type being 'int', it's about it not being 'const'.  The type rules of the language are inconsistent.  At the very least the reflect package should describe the const as 'const int' since it actually make a difference.

Also, there is no way to convert or cast a variable to a const, so that path is blocked.

This also means there is nothing sensible for me to convert my variable integer to that would allow me to multiply.

But, if I convert/cast the variable integer to a time.Duration(), I can multiply the durations together to get the sensible duration.  Problem solved at the cost of some time.  That is, time squared...

 RickyS 

minux

unread,
Jun 19, 2013, 3:51:04 PM6/19/13
to RickyS, golan...@googlegroups.com, Ian Lance Taylor, ehog....@googlemail.com
On Thu, Jun 20, 2013 at 3:43 AM, RickyS <rickys...@gmail.com> wrote:
It depends on whether the integer is const or not.
This program works as expected:
package main
import ("fmt"; "time"; "reflect")
func main () {
  const m = 10
  fmt.Printf("TypeOf(m) is %s\n", reflect.TypeOf(m).Name())
  waiter := time.Duration(3600000000)
  bigwait := m * waiter
  fmt.Printf("waiter is %v, bigwait %v\n", waiter, bigwait)
}
The output is:
TypeOf(m) is int
waiter is 3.6s, bigwait 36s

But change the 'const m' to a 'var m' and the old error message returns:
invalid operation: m * waiter (mismatched types int and time.Duration)
NOTE:  The const is an int according to reflection, and the var is an int according to the error message, so the problem isn't about the type being 'int', it's about it not being 'const'.  The type rules of the language are inconsistent.  At the very least the reflect package should describe the const as 'const int' since it actually make a difference.
Go's constant without explicit type are of a special type: untyped constant.

it will become typed constant (int, time.Duration, float64, complex128, or whatever) _only_ when it is used
(or put it another way, it will have a normal Go type only when it must have).

read more about these rules in the Go spec: 
http://tip.golang.org/ref/spec#Constant_expressions

Jeremy Wall

unread,
Jun 19, 2013, 3:52:08 PM6/19/13
to RickyS, golang-nuts, Ian Lance Taylor, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 2:43 PM, RickyS <rickys...@gmail.com> wrote:
It depends on whether the integer is const or not.
This program works as expected:
package main
import ("fmt"; "time"; "reflect")
func main () {
  const m = 10
  fmt.Printf("TypeOf(m) is %s\n", reflect.TypeOf(m).Name())
  waiter := time.Duration(3600000000)
  bigwait := m * waiter
  fmt.Printf("waiter is %v, bigwait %v\n", waiter, bigwait)
}
The output is:
TypeOf(m) is int
waiter is 3.6s, bigwait 36s

But change the 'const m' to a 'var m' and the old error message returns:
invalid operation: m * waiter (mismatched types int and time.Duration)
NOTE:  The const is an int according to reflection, and the var is an int according to the error message, so the problem isn't about the type being 'int', it's about it not being 'const'.  The type rules of the language are inconsistent.  At the very least the reflect package should describe the const as 'const int' since it actually make a difference.

Since we are dealing in technicalities here the m is not an int. It's a numeric constant. It gets cast to an int when you pass it to the TypeOf function.
 

Also, there is no way to convert or cast a variable to a const, so that path is blocked.

This also means there is nothing sensible for me to convert my variable integer to that would allow me to multiply.

But, if I convert/cast the variable integer to a time.Duration(), I can multiply the durations together to get the sensible duration.  Problem solved at the cost of some time.  That is, time squared...

 RickyS 

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

William Kennedy

unread,
Jun 19, 2013, 4:01:05 PM6/19/13
to golan...@googlegroups.com
Hi Ricky,
Check out my blog on the subject, it might be of some help

Rob Pike

unread,
Jun 19, 2013, 4:38:40 PM6/19/13
to Jeremy Wall, RickyS, golang-nuts, Ian Lance Taylor, minux, ehog....@googlemail.com
Easier way to print a type: fmt.Printf("%T\n", m)

(As observed, though, in your case 'm' is not an int, it's a constant,
but the expression must be given a type when passed to Printf, and
that type is int)

-rob

RickyS

unread,
Jun 19, 2013, 5:05:04 PM6/19/13
to golan...@googlegroups.com, RickyS, Ian Lance Taylor, ehog....@googlemail.com
minux said "it will have a normal Go type only when it must have".
Well, when multiplying by Duration, it seems to me it must have some 'normal' type.

 RickyS

RickyS

unread,
Jun 19, 2013, 5:08:01 PM6/19/13
to golan...@googlegroups.com, RickyS, Ian Lance Taylor, minux, ehog....@googlemail.com
If Jeremy Wall is right, and it seems to me he is, then TypeOf (and reflection) should be in the language and not a package.

Ian Lance Taylor

unread,
Jun 19, 2013, 5:10:08 PM6/19/13
to RickyS, golan...@googlegroups.com, ehog....@googlemail.com
Yes, and that type will be Duration. As the spec says, an untyped
constant will take on the type appropriate to the expression, if
possible.

Ian

RickyS

unread,
Jun 19, 2013, 5:11:00 PM6/19/13
to golan...@googlegroups.com, Jeremy Wall, RickyS, Ian Lance Taylor, minux, ehog....@googlemail.com
This still doesn't explain how we can multiply a Duration by a 'const' and get the answer as if it were an int.

Jeremy Wall

unread,
Jun 19, 2013, 5:10:56 PM6/19/13
to RickyS, golang-nuts, Ian Lance Taylor, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 4:08 PM, RickyS <rickys...@gmail.com> wrote:
If Jeremy Wall is right, and it seems to me he is, then TypeOf (and reflection) should be in the language and not a package.

I'm not sure that really helps. Go constants are not typed in the sense that a variable is. TypeOf for a constant doesn't really make sense.



On Wednesday, June 19, 2013 10:52:08 PM UTC+3, Jeremy Wall wrote:

Since we are dealing in technicalities here the m is not an int. It's a numeric constant. It gets cast to an int when you pass it to the TypeOf function.
 

 

Ian Lance Taylor

unread,
Jun 19, 2013, 5:12:42 PM6/19/13
to RickyS, golan...@googlegroups.com, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 2:08 PM, RickyS <rickys...@gmail.com> wrote:
> If Jeremy Wall is right, and it seems to me he is, then TypeOf (and
> reflection) should be in the language and not a package.

Why? Untyped constants are a purely compile-time construct, required
to make Go's strict type rules work. They don't exist at runtime. At
runtime, everything has a type.

(Actually, TypeOf was in the language in the past--it used to be
unsafe.TypeOf--but we moved it into the reflect package when we
realized that it was only useful as part of reflect.)

Ian

Ian Lance Taylor

unread,
Jun 19, 2013, 5:13:43 PM6/19/13
to RickyS, golan...@googlegroups.com, Jeremy Wall, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 2:11 PM, RickyS <rickys...@gmail.com> wrote:
> This still doesn't explain how we can multiply a Duration by a 'const' and
> get the answer as if it were an int.

If you multiply a value of type Duration by an untyped constant, the
constant will be given the type Duration, and the multiplication will
be computed in the type Duration and will produce a result of the type
Duration.

Ian

RickyS

unread,
Jun 19, 2013, 5:32:22 PM6/19/13
to golan...@googlegroups.com, RickyS, Jeremy Wall, minux, ehog....@googlemail.com
What you say is consistent, as the error message (mismatched types) re-appears when m is declared as:
const m int = 100

But: This means the internal representation of a Duration (or any type) is not truly encapsulated.  If a Duration were typed as a struct that contained an int64 then multiplication by a constant would not work, either.  This breaks my expectations, but my expectations were created by using other languages.

This also means that defining Duration as:
type Duration int64
creates Duration as an alias of int64, which the language docs deny.
It's near midnight where I am, so I am going to bed.  Good night and thank you all very much...

   RickyS

On Thursday, June 20, 2013 12:13:43 AM UTC+3, Ian Lance Taylor wrote:
...

Jeremy Wall

unread,
Jun 19, 2013, 5:34:37 PM6/19/13
to RickyS, golang-nuts, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 4:32 PM, RickyS <rickys...@gmail.com> wrote:
What you say is consistent, as the error message (mismatched types) re-appears when m is declared as:
const m int = 100

But: This means the internal representation of a Duration (or any type) is not truly encapsulated.  If a Duration were typed as a struct that contained an int64 then multiplication by a constant would not work, either.  This breaks my expectations, but my expectations were created by using other languages.

This also means that defining Duration as:
type Duration int64
creates Duration as an alias of int64, which the language docs deny.

It's not an alias it's a new type whose base type is int64. It has a similar effect as an alias but Go's type system treats the two types as seperate and distinct types.

Ian Lance Taylor

unread,
Jun 19, 2013, 5:42:39 PM6/19/13
to RickyS, golan...@googlegroups.com, Jeremy Wall, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 2:32 PM, RickyS <rickys...@gmail.com> wrote:
>
> But: This means the internal representation of a Duration (or any type) is
> not truly encapsulated.

That is correct.

> This also means that defining Duration as:
> type Duration int64
> creates Duration as an alias of int64, which the language docs deny.

In the terminology of the Go spec, a type alias means that two types
can be used interchangeably. Given the declaration above, that is not
true of the types Duration and int64. For example, you can not assign
a value of type int64 to a variable of type Duration.

There is at present no way for a Go program to declare a type alias,
but there are two type aliases in the language: byte is an alias for
uint8, and rune is an alias for uint32.

Ian

minux

unread,
Jun 19, 2013, 5:42:15 PM6/19/13
to RickyS, golan...@googlegroups.com, Jeremy Wall, ehog....@googlemail.com
On Thu, Jun 20, 2013 at 5:32 AM, RickyS <rickys...@gmail.com> wrote:
What you say is consistent, as the error message (mismatched types) re-appears when m is declared as:
const m int = 100
this is not an untyped constant, so that conversion to a suitable type rule doesn't apply anymore.

But: This means the internal representation of a Duration (or any type) is not truly encapsulated.  If a Duration were typed as a struct that contained an int64 then multiplication by a constant would not work, either.  This breaks my expectations, but my expectations were created by using other languages.

This also means that defining Duration as:
type Duration int64
creates Duration as an alias of int64, which the language docs deny.
it doesn't create an alias, it's a new type that happens to share the arithmetic rules of int64.

the rule for Go multiplication is pretty simple, just one rule, both side must be of the same type.

constant could be either typed (like your m above), or untyped (when you say `const m = 100`),
when an untyped constant is used in an expression, say, m * time.Duration(100), then it must
have a type, and as the other side of the expression is typed time.Duration, it is typed time.Duration.

this explains why:
100 * time.Duration(100) works, and also
when m is: const m = 100, m * time.Duration(100) works.
but when m is: const m int = 100, m * time.Duration(100) won't compile.

even if you declare m as: const m int64 = 100, m * time.Duration(100) is still an error.
the only way (if you intend to give m a type at the time of declaration), is:
const m time.Duration = 100

peterGo

unread,
Jun 19, 2013, 7:14:17 PM6/19/13
to golan...@googlegroups.com, RickyS, Jeremy Wall, minux, ehog....@googlemail.com
Ian,


On Wednesday, June 19, 2013 5:42:39 PM UTC-4, Ian Lance Taylor wrote:On Wed, Jun 19, 2013 at 2:32 PM, RickyS <rickys...@gmail.com> wrote:
there are two type aliases in the language: byte is an alias for uint8, and rune is an alias for uint32.

Numeric types
http://golang.org/ref/spec#Numeric_types

rune        alias for int32

Peter

peterGo

unread,
Jun 19, 2013, 7:20:44 PM6/19/13
to golan...@googlegroups.com, RickyS, Jeremy Wall, minux, ehog....@googlemail.com
Correction:


Ian,

On Wednesday, June 19, 2013 5:42:39 PM UTC-4, Ian Lance Taylor wrote:
there are two type aliases in the language: byte is an alias for uint8, and rune is an alias for uint32.

Numeric types
http://golang.org/ref/spec#Numeric_types

rune        alias for int32

Peter

Ian Lance Taylor

unread,
Jun 19, 2013, 7:32:52 PM6/19/13
to peterGo, golan...@googlegroups.com, RickyS, Jeremy Wall, minux, ehog....@googlemail.com
On Wed, Jun 19, 2013 at 4:14 PM, peterGo <go.pe...@gmail.com> wrote:
>
> On Wednesday, June 19, 2013 5:42:39 PM UTC-4, Ian Lance Taylor wrote:On Wed,
> Jun 19, 2013 at 2:32 PM, RickyS <rickys...@gmail.com> wrote:
> there are two type aliases in the language: byte is an alias for uint8, and
> rune is an alias for uint32.
>
> Numeric types
> http://golang.org/ref/spec#Numeric_types
>
> rune alias for int32

Right, thanks for the correction.

Ian
Reply all
Reply to author
Forward
0 new messages