One place for hosting & domains


      RxJS Operators for Dummies: forkJoin, zip, combineLatest, withLatestFrom

      If you are confused about the differences between forkJoin, zip, combineLatest and withLatestFrom, you are not alone! 🙂

      These 4 operators are what we know as combination operators – we use them when we need to join information from multiple observables.

      Which operator should I use?

      That is what this article is for! We will talk about the usage and differences between these 4 operators in an easy to understand way, so you know which one to choose when the time comes.


      Imagine you are printing t-shirts. Ms. Color holds the color information and Mr. Logo holds the logo information. Both of them will pick color and logo spontaneously. You will need to wait and combine these two information continuously in order to print t-shirts. Ms. Color and Mr. Logo represent two observables in our code – color$ and logo$.

      you, ms. color & mr. logo

      // 0. Import Rxjs operators
      import { forkJoin, zip, combineLatest, Subject } from 'rxjs';
      import { withLatestFrom, take, first } from 'rxjs/operators';
      // 1. Define shirt color and logo options
      type Color="white" | 'green' | 'red' | 'blue';
      type Logo = 'fish' | 'dog' | 'bird' | 'cow';
      // 2. Create the two persons - color and logo observables, 
      // They will communicate with us later (when we subscribe)
      const color$ = new Subject<Color>();
      const logo$ = new Subject<Logo>();
      // 3. We are ready to start printing shirt. Need to subscribe to color and logo observables to produce shirts, we will write code here later
      // 4. The two persons(observables) are doing their job, picking color and logo
      // 5. When the two persons(observables) has no more info, they said bye bye.. We will write code here later

      I guess the code above is pretty expressive itself. We created two observables by using Subject. For part 4 in the code, every .next(<value>) means Ms. Color or Mr. Logo is picking color or logo.

      Take note of the sequence of information (part 4 in our code), here is the summary:-

      sequence of info

      1. Ms. Color picks WHITE
      2. Mr. Logo picks FISH
      3. Ms. Color picks GREEN
      4. Mr. Logo picks DOG
      5. Ms. Color picks RED
      6. Mr. Logo picks BIRD
      7. Ms. Color picks BLUE

      Later, we will update our code (part 3 & 5) to subscribe to both color and logo observables using the 4 different operators to see how the shirts are produced differently.

      All set. Let’s start exploring our first operator!

      zip – the love birds operator

      I call zip operator the love birds operator. Love birds need to always be together. Remember Titanic, the “you jump, I jump” type.

      Let’s replace our code (part 3) with below:

      // 3. We are ready to start printing shirt...
      zip(color$, logo$)
          .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));


      For those of you who are not familar with JavaScript ES6/ES2015 destructuring assignment, you might find the syntax in subscribe [color, logo] a little bit odd.

      When we zip color$ and logo$, we expect to receive an array of 2 items during subscribe, first item is color and second is logo (follow their orders in zip function).

      The traditional way of writing it would be .subscribe((data) => console.log(${data[0]} shirt with ${data[1]})). As you can see, it’s not very obvious that data[0] is color.

      ES6 allows us to unpack the value from arrays. Therefore, we unpack data into [color, logo] straight away. More readable right?


      Alright, let’s go back to our code and run it. The shirt printing result would be:-

      zip - printed shirts

      Here is what get to log in the console:

      1. white shirt with fish
      2. green shirt with dog
      3. red shirt with bird

      How does zip work?

      Again, zip operator is the love birds operator. In our case, color will wait for logo whenever there are new value (vice versa). Both values must change then only the log gets triggered.

      1. Ms. Color picks WHITE
      2. Mr. Logo picks FISH <- log 01, WHITE + FISH in pair, love birds!
      3. Ms. Color picks GREEN
      4. Mr. Logo picks DOG <- log 02, GREEN + DOG in pair, love birds!
      5. Ms. Color picks RED
      6. Mr. Logo picks BIRD <- log 03, RED + BIRD in pair love birds!
      7. Ms. Color picks BLUE <- waiting for love...

      zip operator can accept more than 2 observables – no matter how many observables, they must all wait for each other, no man left behind!

      combineLatest – the go dutch operator

      I call combineLatest operator the go dutch operator. They are independent and doesn’t wait for each other, they take care of themselves.

      Let’s replace the setup code part 3 with the below code:

      // 3. We are ready to start printing shirt...
      combineLatest(color$, logo$)
          .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

      The shirt printing result would be:-

      combinedLatest - printed shirts

      Here is what get to log in the console:

      1. white shirt with fish
      2. green shirt with fish
      3. green shirt with dog
      4. red shirt with dog
      5. red shirt with bird
      6. blue shirt with bird

      How does combineLatest work?

      As mentioned, combineLatest is the go dutch operator – once they meet their mates one time, they will wait for no man. In our case, first function is triggered after both color and logo values change. There onwards, either color or logo value changed will trigger the log.

      1. Ms. Color picks WHITE 
      2. Mr. Logo picks FISH <- log 01, color + logo first meet, let's go dutch!
      3. Ms. Color picks GREEN <- log 02, GREEN + FISH
      4. Mr. Logo picks DOG <- log 03, DOG + GREEN
      5. Ms. Color picks RED <- log 04, RED + DOG
      6. Mr. Logo picks BIRD <- log 05 BIRD + RED 
      7. Ms. Color picks BLUE <- log 06 BLUE + BIRD

      withLatestFrom – the master slave operator

      I call withLatestFrom operator the master slave operator. At first, master must meet the slave. After that, the master will take the lead, giving command. The slave will just follow and has no voice. 🙁

      Let’s replace the setup code part 3 with the below code:

      // 3. We are ready to start printing shirt...
          .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

      The shirt printing result would be:-

      withLatestFrom - printed shirts

      Here is what get to log in the console:

      1. green shirt with fish
      2. red shirt with dog
      3. blue shirt with bird

      How does withLatestFrom work?

      Can you guess who is the master and who is the slave in our case?

      You guessed it! color is the master while logo is the slave. At first (only once), color(master) will look for logo(slave). Once the logo(slave) has responded, color(master) will take the lead. Log will get triggered whenever the next color(master) value is changed. The logo(slave) value changes will not trigger the console log.

      1. Ms. Color picks WHITE <- nothing happen, waiting for slave
      2. Mr. Logo picks FISH <- slave found, wait for the master's command
      3. Ms. Color picks GREEN <- log 01, master says GREEN! So, GREEN + FISH
      4. Mr. Logo picks DOG
      5. Ms. Color picks RED <- log 02, master says RED! So, RED + DOG
      6. Mr. Logo picks BIRD
      7. Ms. Color picks BLUE <- log 03 master says BLUE! So, BLUE + BIRD

      forkJoin – the final destination operator

      Definitely not the horror movie) kind of final destination! I call forkJoin operator the final destination operator because they are very serious, they only commit once all parties are very sure that they are completely true, final destination of each other.

      Let’s replace the setup code part 3 with the below code:

      // 3. We are ready to start printing shirt...
      forkJoin(color$, logo$)
          .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

      The shirt printing result would be:-
      forkJoin - printed shirts

      You see it right, the result is NOTHING! There is no log in console.

      How does forkJoin work?

      forkJoin is the final destination operator! They are very serious to make sure each other are their final destination. In our code, both color and logo observables are not complete, we can keep pushing value by calling .next – that means they are not serious enough and thus they are not final destination of each other.

      So, how do we be serious?

      We need to complete both observables. Let’s replace our setup code part 5 with the below:

      // 5. When the two persons(observables) ...

      Great! With the above code changes, Here is our shirt printing result:-

      forkJoin (complete) - printed shirts

      Here is what get to log in the console:

      1. blue shirt with bird

      Here is the sequence of when the log happens:-

      1. Ms. Color picks WHITE
      2. Mr. Logo picks FISH
      3. Ms. Color picks GREEN
      4. Mr. Logo picks DOG
      5. Ms. Color picks RED
      6. Mr. Logo picks BIRD
      7. Ms. Color picks BLUE
      8. Ms. Color completed <-- color is serious!
      9. Mr. Logo completed <--- log no 01, both logo & color are completed. Final destination!

      There is more than one way to complete observable. There are operators that allow you to auto complete observable when conditions met, for example take, takeUntil, first.

      Let’s say, you only want to make 1 shirt, you only need to know the first color and logo, In this case, you don’t care about the rest of the info that Ms. Color & Mr. Logo provide. You can make use of take or first operator to achieve auto complete observable once first color and logo emit.

      Let’s replace the setup code part 3 with the below code:

      // 3. We are ready to start printing shirt...
      const firstColor$ = color$.pipe(take(1));
      const firstLogo$ = logo$.pipe(first());
      forkJoin(firstColor$, firstLogo$)
          .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

      You can remove all the code in part 5 as well, we don’t need the two lines .complete() (as previous code) because take and first will auto complete the observable when the condition met.

      With the above change, you should see a white shirt with fish!

      forkjoin (auto complete) - printed shirtst


      Phew~ this is a pretty long article huh? Here is the summary of all results.
      one page answer

      Let’s wrap up! In summary, these 4 operators trigger the next action (subscribe function in our case) in slightly different conditions:

      • zip – the love birds, always work as a team, triggers only when all observables return new values
      • combineLatest – the go dutch, start trigger once all observables return new values, then wait for no man, trigger every time when either observable return new value.
      • withLatestFrom – the master slave, master first waits for slave, after that, action get triggered every time only when master return new value.
      • forkJoin – the final destination, trigger once when all observables have completed.

      Which operator should I use?

      So I guess you can answer “which operator should I use?” better now. As a general rule of thumb – choose the one that works for you. In some cases, the outcome of using different operators might be the same (that’s why people get confused on which one to use), it would be good to understand the intention of the operator & decide accordingly.

      One of the most common use case of combination operators would be calling a few apis, wait for all results return, then executing next logic. Either forkJoin or zip will work and return same result because api calls are one-time only, auto-completed once result is returned (e.g. Angular httpClient.get).

      However, by understanding the operators more, forkJoin might be more suitable in this case. It is because we “seriously” want to wait for all http responses to complete before proceed to the next step. zip is intended for observables with multiple emits. In our case, we expect only one emit for each http request. Therefore, I think forkJoin is more appropriate (oh well, either way, your code will run just fine & return the same result, but it’s good to know right?).


      Alright, here is the final code. Please note that the code is a little bit different from demo because I include the code to draw the UI. Logic and general code structure stay the same though.

      See the Demo on Stackblitz


      As a bonus, let me give you a quiz!


      Figure out the correct results with the provided code. Feel free to play around with it, and explore different scenarios (add more more observables maybe?)!

      Quiz Answer: Click here for the quiz’s answer! (please try yourself first)

      That’s all. Happy coding!

      Source link

      JavaScript Unary Operators: Simple and Useful

      You might have come across things like i++, –i in loops or ** !** when writing conditions. Ever wondered how these operations work? Well, these are unary operators and we are going to take an in-depth look into how they work.

      What is an operator?

      Mathematically, an operation is a calculation on one or more values called operands mapping to an output value. An operator is a symbol/sign that maps operands to output values.

      What is an unary operator?

      A unary operator is one that takes a single operand/argument and performs an operation.

      A unary operation is an operation with only one operand. This operand comes either before or after the operator.
      Unary operators are more efficient than standard JavaScript function calls. Additionally, unary operators can not be overridden, therefore their functionality is guaranteed.

      Summary of all unary operators

      Operator Explanation
      Unary plus (+) Tries to convert the operand into a number
      *Unary negation (-) * Tries to convert the operand into a number and negates after
      Logical Not (!) Converts to boolean value then negates it
      Increment (++) Adds one to its operand
      Decrement (–) Decrements by one from its operand
      Bitwise not (~) Inverts all the bits in the operand and returns a number
      typeof Returns a string which is the type of the operand
      delete Deletes specific index of an array or specific property of an object
      void Discards a return value of an expression.

      Unary plus (+)

      This operator precedes the operand and tries to convert it to a number.

      It can convert all string representations of numbers, boolean values(true and false) and null to numbers. Numbers will include both integers, floats, hexadecimal, scientific (exponent) notation and Infinity.

      If the operand cannot be converted into a number, the unary plus operator will return NaN.


          +3                                   // returns 3
          +'-3'                                // returns -3
          +'3.14'                              // returns 3.14
          +'3'                                 // returns 3
          +'0xFF'                              // returns 255
          +true                                // returns 1
          +'123e-5'                            // returns 0.00123
          +false                               // returns 0
          +null                                // returns 0
          +'Infinity'                          // returns Infinity
          +'infinity'                          // returns NaN
          +function(val){  return val }        // returns NaN

      The illustration above clearly shows how the + operator will behave when applied to different data types.

      • Numbers will not be altered.
      • A string notation of a number e.g ‘3’ is converted to that number (3).
      • Boolean value true is converted to a 1 and false to 0.
      • Other types e.g functions and objects are converted to NaN.


      An object can only be converted if it has a key valueOf and it’s function returns any of the above types.

        valueOf: function(){
          return '0xFF'
      //returns 255

      Unary negation (-)

      It also precedes the operand and converts non-numbers data types to numbers like unary plus, however, it performs an additional operation, negation.

      Unary plus is considered the fastest and preferred way of making conversions because it doesn’t perform any additional operation.
      Both the unary negation and plus perform the same operation as the Number() function for non-numbers.


          -3                               // returns -3
          -'-3'                            // returns 3
          -'3.14'                          // returns -3.14
          -'3'                             // returns -3
          -'0xFF'                          // returns -255
          -true                            // returns -1
          -'123e-5'                        // returns -0.00123
          -false                           // returns -0
          -null                            // returns -0
          -'Infinity'                      // returns -Infinity
          -'infinity'                      // returns NaN
          -function(val){  return val }    // returns NaN
        -{     valueOf: function(){
            return '0xFF'
        }                                //returns -255

      Logical Not (!)

      This operator comes before the operand. It converts the operand into it’s boolean equivalent before negating it.


      !false        // returns true
      !NaN          // returns true
      !0            // returns true
      !null         // returns true
      !undefined    // returns true
      !""           // returns true
      !true         // returns false
      !-3           // returns false
      !"-3"         // returns false
      !42           // returns false
      !"42"         // returns false
      !"foo"        // returns false
      !"true"       // returns false
      !"false"      // returns false
      !{}           // returns false
      ![]           // returns false
      !function(){} // returns false

      The above illustration demonstrates how logical not returns ** false** if the operand can be converted to true, if not it returns false.

      You can use double negation(!!)

      Let us take a look at a more awesome example:

      !!'hi' === true  // returns true
      !!1 === true    // returns true
      !!0 === false  // returns true

      Why true?
      So we execute from right to left.

      !'hi'  //returns false


      !false //returns true


      true === true //returns true

      Increment (++)

      This operator adds one to its operand and returns the result.

      It can be used as a postfix or prefix operator.

      • Postfix : – meaning the operator comes after the operand(y++). This returns the value before incrementing.
      • Prefix: – the operator comes before the operand (++y). Using it as a prefix, returns the value after incrementing.



      x = 4      // x=4
      y = x++    // y = 4 and  x = 5
      // y is set to the value before incrementing and it adds 1 to x
      // Be careful about resetting values when using postfix
      var a = 5     // a = 5
      a = a++       // a = 5
      // a is set to the value before incrementing


      x = 4      // x=4
      y = ++x    // y = 5 and  x = 5
      // y is set to the value after incrementing and it adds 1 to x
      var a = 5     // a = 5
      a = ++a       // a = 6
      // a is set to the value after incrementing

      Decrement (–)

      The decrement operator subtracts one from its operand.

      It returns a value before decrementing if it is postfix. Prefixing it returns the value after decrementing.



      var a = 5     // a = 5
      a = a--       // a = 5
      // a is set to the value before incrementing
      x = 4      // x=4
      y = x--    // y = 4 and  x = 3
      // sets y to the value before decrementing and it removes 1 from x


      var a = 5  // a = 5
      a = --a    // a = 4
      // a is set to the value after incrementing
      x = 4      // x=4
      y = --x    // y =3 and  x = 3
      // sets y to the value after incrementing and it adds 1 to x

      Bitwise not (~)

      Performs a binary NOT operation, by inverting all the bits in the operand and return a number.

      A bitwise not on a number results in: -(x + 1).


      ~2                                  //returns -3
      ~'2'                                //returns -3
      ~'-3'                               // returns 2
      -'-3.14'                            // returns 2
      ~'-3.54'                            // returns 2
      ~'0xFF'                             // returns -256
      ~true                               // returns -2
      ~'123e-5'                           // returns -1
      ~false                              // returns -1
      ~null                               // returns -1
      ~'Infinity'                         // returns -1
      ~'infinity'                         // returns -1
      ~function(val){  return val }       // returns -1
      ~{     valueOf: function(){
              return '0xFF'
      }                                  //returns -256

      The table below takes a deeper look into how this operation is performed.

      (base 10) (base 2) Not (base 2) Not (base 10)
      2 00000010 11111101 -3
      1 00000001 11111110 -2
      0 00000000 11111111 -1
      -1 11111111 00000000 0
      -2 11111110 00000001 1
      -3 11111101 00000010 2


      This operator comes before the operand. It returns a string indicating the data type of the operand.


      typeof 2                                       // returns 'number'
      typeof -3.14                                   // returns 'number'
      typeof 0xFF                                    // returns 'number'
      typeof 123e-5                                  // returns 'number'
      typeof true                                    // returns 'boolean'
      typeof false                                   // returns 'boolean'
      typeof null                                    // returns 'object'
      typeof Infinity                                // returns 'number'
      typeof '2'                                     // returns 'string'
      typeof '-3'                                    // returns 'string'
      typeof 'infinity'                              // returns 'string'
      typeof Date()                                  // returns 'string'
      typeof [1,2,3]                                 // returns 'object'
      typeof {hi: 'world'}                           // returns 'object'
      typeof function(val){  return val }            // returns 'function'
      typeof {     valueOf: function(){
              return '0xFF'
      }                                              // returns 'object'
      typeof undefined                               // returns 'undefined'
      typeof hi                                      // returns 'undefined'
      typeof NaN                                     // returns 'number'
      typeof new Date()                              // returns 'object'
      typeof /ab+c/                                  // returns 'object'
      typeof new RegExp('ab+c')                      // returns 'object'
      typeof document                                // returns 'undefined'


      It also comes before the operand. It deletes values of a specific index of an array and a specific property of an object.

      It returns true if it successfully deleted the property or if the property does not exist.
      It returns** false** if it fails to delete an item.

      Delete does not have any effect on both functions and variables. Let’s look at the following examples.

      // Deleting a variable
      var hi = 1;
      delete hi;          // returns false
      console.log(hi);    // returns 1
      // Deleting a function
      function yo(){ };
      delete yo;           // returns false
      console.log(yo);     // returns function foo(){ }
      // Deleting an object
      var pub = {bar: '1'}
      delete pub           // returns false
      console.log(pub);    // returns {bar: '1'}
      //Deleting an array
      var code = [1,1,2,3,5]
      delete code          // returns false
      console.log(code);   //  [1,1,2,3,5]


      As earlier stated, it deletes the property or the whole object.

      // Deleting a property with the literal notation
      var fruits = {1: 'apple', 2: 'mango'}
      delete fruits[1]             // returns true
      console.log(fruits);         // returns { '2': 'mango' }
      console.log(fruits[1]);      // returns undefined
      // Deleting a property with the dot notation
      var pub = { bar: "42" };
      delete;              // returns true
      console.log(pub);            // returns {}
      // Deleting a property that does not exist
      var lunch = { fries: 1 };
      delete lunch.beans;          // returns true
      console.log(lunch);          // returns { fries: 1 }
      // Deleting a non-configurable property of a predefined object
      delete Math.PI;              // returns false console.log(Math.PI);        // returns 3.141592653589793

      Non-Configurable properties

      Delete has no effect on an object property that is as non-configurable. It will always return false.
      In strict mode, this will raise a SyntaxError.


      // When Non Configurable
      var Person = {};
      Object.defineProperty(Person, 'name', {  value: 'Scot', configurable: false })
      // Defines an object property and sets it to non-configurable
      console.log(Person.value);                                    // returns 'Scot'
      delete Person.value                                           // returns false
      console.log(Person.value);                                    // returns 'Scot'
      // When configurable
      var b = {};
      Object.defineProperty(Person, 'name', {  value: 'Scot', configurable: true })
      console.log(b.value);                                    // returns 'Scot'
      delete b.value                                           // returns true
      console.log(b.value);                                    // returns undefined

      Read more about defineProperty()

      var, let and const create non-configurable properties that cannot be deleted with the delete operator:


      var num = 1;
      // We can access this global property using:
      Object.getOwnPropertyDescriptor(window, 'num') // returns { value: 'XYZ',
      //           writable: true,
      //           enumerable: true,
      //           configurable: false } delete num;                                     // returns false
      // Node
      Object.getOwnPropertyDescriptor(global, 'num')
      // returns { value: 'XYZ',
      //           writable: true,
      //           enumerable: true,
      //           configurable: false }
      // regular objects
      var lunch = { fries: 1 }; Object.getOwnPropertyDescriptor(lunch, 'fries')
      // returns { value: 1,
      //           writable: true,
      //           enumerable: true,
      //           configurable: true }

      Notice that the var keyword is marked as non-configurable


      Arrays are considered type object in javascript. Thus this method will work on them.


      // Deleting values of an array index
      var lol=[20,30,40];
      console.log(lol.length);     // returns 3
      delete lol[2]                // returns true
      console.log(lol);            // returns [ 20, 30,  ]
      console.log(lol[2]);         // returns undefined
      console.log(lol.length);     // returns 3


      The delete operator will only delete the value and *not the index *of the array. It will leave the value of that particular index as undefined. This is why the length does not change.

      strict mode

      In strict mode, delete throws a SyntaxError due to the use of direct reference to a variable, a function argument or a function name.

      ‘use strict’
      var fruits = {1:'mango', 2:'apple'};
      delete fruits;
      // Output: Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
      function Person() {
       delete name;             // SyntaxError
       var name; }
      function yo() {
      delete yo; // SyntaxError

      Here are a few pointers to always consider when using delete:

      • Trying to delete a property that does not exist, delete will return true but will not have an effect on the object.

      • Delete only affects object own properties. This means if a property with the same name exists on the object’s prototype chain, then delete will not affect it. After deletion, the object will use the property from the prototype chain.

      • Variable declared var,_ let_ and const cannot be deleted from the global scope or from a function’s scope.

        • Meaning:- Delete cannot delete any functions in the global scope or in the function scope.
        • Delete works on functions which are part of an object (apart from the global scope).
      • Non-configurable properties cannot be removed.

      • Delete does not work on any of the built-in objects like Math, Array, Object or properties that are created as non-configurable with methods like Object.defineProperty().

      Void operator:

      It precedes an operation. It discards the return value of an expression, meaning it evaluates an expression but returns undefined.

      Void operator’s main purpose is to return undefined. The void operator specifies an expression to be evaluated without returning a value.

      The void operator is used in either of the following ways:
      void (expression)
      void expression


      The void operator is not a function, so () are not required, but it is good style to use them according to MDN


      void 0                                              // returns undefined
      var hi = function () {
          return 4;
      var result = hi()                                   // logs 'Yap' and returns 4
      console.log(result);                                // returns 4
      var voidResult = void (hi())                        // logs 'Yap' and returns undefined
      console.log(voidResult);                             // returns undefined

      The void operator can be used to specify an expression as a hypertext link. The expression is evaluated but is not loaded in place of the current document.

      Some more examples

      <a href="">Click here to do nothing</a>

      The code above creates a link that does nothing when a user clicks it. This is because void(0) evaluates to undefined.

      <a href="">
      Click here to submit</a>

      The code creates a link that submits a form when the user clicks it.


      Always consider the order of operations when dealing with more than one operator. This is good practice in mitigating unforeseen bugs.

      Here is a brief table that shows the order of precedence in operations when using Javascript. Operands on the same level have the same order of precedence.

      Operator type Operators Example
      member . [] [1,2,3]
      call / create instance () new var vehicle = new Vehicle();
      negation/increment ! ~ – + ++ – typeof void delete typeof [1,2,2]
      multiply/divide * / % 3 % 3
      addition/subtraction + – 3 + 3
      bitwise shift << >> >>> 9 << 2
      relational < <= > >= in instanceof [1] instanceof Array
      *equality * == != === !== void(0) === undefined
      bitwise-and & 5 & 1
      *bitwise-xor * ^ 5 ^ 1
      logical-and && x < 10 && y > 1
      conditional ?: (age < 18) ? “Too young”:“Old enough”
      assignment = += -= *= /= %= <<= >>= >>>= &= ^= =
      *comma * , b = 3, c = 4

      Source link

      How To Do Math in Go with Operators

      Numbers are common in programming. They are used to represent things such as: screen-size dimensions, geographic locations, money and points, the amount of time that passes in a video, positions of game avatars, colors through assigning numeric codes, and so on.

      Effectively performing mathematical operations in programming is an important skill to develop because of how frequently you’ll work with numbers. Though a high-level understanding of mathematics can certainly help you become a better programmer, it is not a prerequisite. If you don’t have a background in mathematics, try to think of math as a tool to accomplish what you would like to achieve, and as a way to improve your logical thinking.

      We’ll be working with two of Go’s most used numeric data types, integers and floats:

      • Integers are whole numbers that can be positive, negative, or 0 (…, -1, 0, 1, …).
      • Floats are real numbers that contain a decimal point, like 9.0 or -2.25..

      This tutorial will review operators that we can use with number data types in Go.


      An operator is a symbol or function that indicates an operation. For example, in math the plus sign or + is the operator that indicates addition.

      In Go, we will see some familiar operators that are brought over from math. However, other operators we will use are specific to computer programming.

      Here is a quick reference table of math-related operators in Go. We’ll be covering all of the following operations in this tutorial.

      Operation What it returns
      x + y Sum of x and y
      x - y Difference of x and y
      -x Changed sign of x
      +x Identity of x
      x * y Product of x and y
      x / y Quotient of x and y
      x % y Remainder of x / y

      We’ll also be covering compound assignment operators, including += and *=, that combine an arithmetic operator with the = operator.

      Addition and Subtraction

      In Go, addition and subtraction operators perform just as they do in mathematics. In fact, you can use the Go programming language as a calculator.

      Let’s look at some examples, starting with integers:

      fmt.Println(1 + 5)



      Instead of passing integers directly into the fmt.Println statement, we can initialize variables to stand for integer values by using syntax like the following:

      a := 88
      b := 103
      fmt.Println(a + b)



      Because integers can be both positive and negative numbers (and 0 too), we can add a negative number with a positive number:

      c := -36
      d := 25
      fmt.Println(c + d)



      Addition will behave similarly with floats:

      e := 5.5
      f := 2.5
      fmt.Println(e + f)



      Because we added two floats together, Go returned a float value with a decimal place. However, since the decimal place is zero in this case, fmt.Println dropped the decimal formatting. To properly format the output, we can use fmt.Printf and the verb %.2f, which will format to two decimal places, like this example:

      fmt.Printf("%.2f", e + f)



      The syntax for subtraction is the same as for addition, except we change our operator from the plus sign (+) to the minus sign (-):

      g := 75.67
      h := 32.0
      fmt.Println(g - h)



      In Go, we can only use operators on the same data types. We can’t add an int and a float64:

      i := 7
      j := 7.0
      fmt.Println(i + j)


      i + j (mismatched types int and float64)

      Trying to use operators on data types that are not the same will result in a compiler error.

      Unary Arithmetic Operations

      A unary mathematical expression consists of only one component or element. In Go we can use the plus and minus signs as a single element paired with a value to: return the value’s identity (+), or change the sign of the value (-).

      Though not commonly used, the plus sign indicates the identity of the value. We can use the plus sign with positive values:

      i := 3.3



      When we use the plus sign with a negative value, it will also return the identity of that value, and in this case it would be a negative value:

      j := -19



      With a negative value the plus sign returns the same negative value.

      The minus sign, however, changes the sign of a value. So, when we pass a positive value we’ll find that the minus sign before the value will return a negative value:

      k := 3.3



      Alternatively, when we use the minus sign unary operator with a negative value, a positive value will be returned:

      j := -19



      The unary arithmetic operations indicated by the plus sign and minus sign will return either the value’s identity in the case of +i, or the opposite sign of the value as in -i.

      Multiplication and Division

      Like addition and subtraction, multiplication and division will look very similar to how they do in mathematics. The sign we’ll use in Go for multiplication is * and the sign we’ll use for division is /.

      Here’s an example of doing multiplication in Go with two float values:

      k := 100.2
      l := 10.2
      fmt.Println(k * l)



      In Go, division has different characteristics depending on the numeric type we’re dividing.

      If we’re dividing integers, Go’s / operator performs floor division, where for the quotient x the number returned is the largest integer less than or equal to x.

      If you run the following example of dividing 80 / 6, you’ll receive 13 as the output and the data type will be int:

      package main
      import (
      func main() {
          m := 80
          n := 6
          fmt.Println(m / n)



      If the desired output is a float, you have to explicitly convert the values before dividing.

      You can do this by wrapping your desired float type of float32() or float64() around your values:

      package main
      import (
      func main() {
          s := 80
          t := 6
          r := float64(s) / float64(t)




      The % operator is the modulo, which returns the remainder rather than the quotient after division. This is useful for finding numbers that are multiples of the same number.

      Let’s look at an example of the modulo:

      o := 85
      p := 15
      fmt.Println(o % p)



      To break this down, 85 divided by 15 returns the quotient of 5 with a remainder of 10. Our program returns the value 10 here, because the modulo operator returns the remainder of a division expression.

      To do modulus math with float64 data types, you’ll use the Mod function from the math package:

      package main
      import (
      func main() {
          q := 36.0
          r := 8.0
          s := math.Mod(q, r)



      Operator Precedence

      In Go, as in mathematics, we need to keep in mind that operators will be evaluated in order of precedence, not from left to right or right to left.

      If we look at the following mathematical expression:

      u = 10 + 10 * 5

      We may read it left to right, but multiplication will be done first, so if we were to print u, we would receive the following value:



      This is because 10 * 5 evaluates to 50, and then we add 10 to return 60 as the final result.

      If instead we would like to add the value 10 to 10, then multiply that sum by 5, we use parentheses in Go just like we would in math:

      u := (10 + 10) * 5



      One way to remember the order of operation is through the acronym PEMDAS:

      Order Letter Stands for
      1 P Parentheses
      2 E Exponent
      3 M Multiplication
      4 D Division
      5 A Addition
      6 S Subtraction

      You may be familiar with another acronym for the order of operations, such as BEDMAS or BODMAS. Whatever acronym works best for you, try to keep it in mind when performing math operations in Go so that the results that you expect are returned.

      Assignment Operators

      The most common assignment operator is one you have already used: the equals sign =. The = assignment operator assigns the value on the right to a variable on the left. For example, v = 23 assigns the value of the integer 23 to the variable v.

      When programming, it is common to use compound assignment operators that perform an operation on a variable’s value and then assign the resulting new value to that variable. These compound operators combine an arithmetic operator with the = operator. Therefore, for addition we’ll combine + with = to get the compound operator +=. Let’s see what that looks like:

      w := 5
      w += 1



      First, we set the variable w equal to the value of 5, then we use the += compound assignment operator to add the right number to the value of the left variable, and then assign the result to w.

      Compound assignment operators are used frequently in the case of for loops, which you’ll use when you want to repeat a process several times:

      package main
      import "fmt"
      func main() {
          values := []int{0, 1, 2, 3, 4, 5, 6}
          for _, x := range values {
              w := x
              w *= 2


      0 2 4 6 8 10 12

      By using a for loop to iterate over the slice called values, you were able to automate the process of the *= operator that multiplied the variable w by the number 2 and then assigned the result back into the variable w.

      Go has a compound assignment operator for each of the arithmetic operators discussed in this tutorial.

      To add then assign the value:

      y += 1

      To subtract then assign the value:

      y -= 1

      To multiply then assign then value:

      y *= 2

      To divide then assign the value:

      y /= 3

      To return the remainder then assign the value:

      y %= 3

      Compound assignment operators can be useful when things need to be incrementally increased or decreased, or when you need to automate certain processes in your program.


      This tutorial covered many of the operators you’ll use with the integer and float numeric data types. You can learn more about different data types in Understanding Data Types in Go and How To Convert Data Types.

      Source link