Implicit, Explicit, Nominal, Structuring and Duck Typing

Implicit, Explicit, Nominal, Structuring and Duck Typing

Today I was a bit confused by the topic chosen for the day. I kept wondering what is implicit, explicit and most of all Duck Typing. The more I pondered the more curious I get.

Join me as we demystify these topics in Javascript first we should have a dictionary definition according to google:

  • Implicit(inferred, understood, hinted) - Suggested though not directly expressed.

    In a Sentence: Mama Mboga's implicit pricing strategy was to give discounts to regular customers buying in bulk.

  • Explicit(clear, direct, plain) - Stated clearly and in detail, leaving no room for confusion or doubt.

    In a Sentence: Through explicit communication, Mama Mboga made it clear that the prices of her vegetables were fixed and non-negotiable, even for her regular customers.

  • Nominal(formal, official) - Existing in name only.

  • Structuring - Construct or arrange according to a plan; give a pattern or organization.

  • Duck Typing - According to Wikipedia, is an application of the duck test—"If it walks like a duck and it quacks like a duck, then it must be a duck"—to determine whether an object can be used for a particular purpose. With nominative typing, an object is of a given type if it is declared to be.

Having understood the basic meanings of these terms, let's now have a look at what they mean in Javascript and how they are used.

Implicit In Javascript

In JavaScript, implicit behavior refers to actions that occur automatically without being explicitly stated in the code.

Here are some examples of implicit behavior in JavaScript:

  1. Type coercion: JavaScript automatically converts data types to a common type when performing operations. For example, if you add a number to a string using the "+" operator, JavaScript will implicitly convert the number to a string and concatenate the two values.

  2. Default values: When a function is called with missing arguments, JavaScript will set the missing values to undefined by default.

  3. Global scope: If you use a variable without declaring it using the "var", "let", or "const" keywords, JavaScript will automatically create a global variable with the same name, which can lead to unexpected behavior.

  4. Truthy and falsy values: In JavaScript, some values are considered "truthy" (e.g., non-empty strings, numbers other than zero) and others are considered "falsy" (e.g., empty strings, zero, undefined). When evaluating expressions, JavaScript will implicitly convert values to their corresponding truthy or falsy values.

  5. Binding of "this": The value of the "this" keyword inside a function depends on how the function is called. If the function is called a method of an object, "this" will refer to the object. If the function is called without an explicit context, "this" will refer to the global object.

When comparing values using the double equals (==) operator, JavaScript will perform implicit type conversion to compare values of different types. Similarly, when a function is called without a specified "this" context, JavaScript will use the global "this" context, which is implicit behavior. Understanding implicit behavior in JavaScript is important for writing efficient and bug-free code.

// Type coercion
let result = "2" + 3;
console.log(result); // Output: "23"

// Default values
function greet(name) {
  name = name || "stranger";
  console.log("Hello, " + name + "!");
}
greet(); // Output: "Hello, stranger!"

// Global scope
function foo() {
  bar = 10;
}
foo();
console.log(bar); // Output: 10

// Truthy and falsy values
function isTruthy(value) {
  if (value) {
    console.log(value + " is truthy");
  } else {
    console.log(value + " is falsy");
  }
}
isTruthy(1); // Output: "1 is truthy"
isTruthy(""); // Output: " is falsy"

// Binding of "this"
let person = {
  name: "John",
  sayHello: function() {
    console.log("Hello, " + this.name + "!");
  }
};
let sayHello = person.sayHello;
sayHello(); // Output: "Hello, undefined!"

In the code above, you can see how implicit behavior occurs in different scenarios such as type coercion, default values, global scope, truthy and falsy values, and binding of "this". Understanding these behaviors is essential for writing effective and bug-free code in JavaScript.

Explicit In Javascript

In Javascript, explicit behavior refers to actions that are explicitly stated in the code and require specific instruction to occur.

Here are some examples of explicit behavior in JavaScript:

  1. Type conversion: Unlike implicit type coercion, type conversion in JavaScript requires explicit instruction to convert a value from one type to another. For example, you can use the Number() function to convert a string to a number, or the String() function to convert a number to a string.

  2. Method invocation: When a function is called a method of an object, you can explicitly set the value of "this" using the call() or apply() methods.

  3. Variable scoping: In JavaScript, you can use the "var", "let", or "const" keywords to explicitly declare variables and control their scope.

  4. Conditional statements: Using if-else statements, switch statements, and ternary operators allow you to explicitly control the flow of your code based on specific conditions.

  5. Iteration: JavaScript provides explicit ways to iterate over arrays, objects, and other collections using loops, while loops, and forEach() methods.

Here's an example code that illustrates explicit behavior in JavaScript:

// Type conversion
let numString = "10";
let num = Number(numString);
console.log(typeof num); // Output: "number"

// Method invocation
let person1 = {
  name: "John",
  age: 30
};
let person2 = {
  name: "Jane",
  age: 25
};
function greet() {
  console.log("Hello, " + this.name + "!");
}
greet.call(person1); // Output: "Hello, John!"
greet.call(person2); // Output: "Hello, Jane!"
// Variable scoping
function foo() {
  var x = 1;
  let y = 2;
  const z = 3;
  console.log(x, y, z);
}
foo(); // Output: 1 2 3

// Conditional statements
let num1 = 10;
let num2 = 20;
if (num1 > num2) {
  console.log(num1 + " is greater than " + num2);
} else {
  console.log(num2 + " is greater than " + num1);
}

// Iteration
let nums = [1, 2, 3, 4, 5];
for (let i = 0; i < nums.length; i++) {
  console.log(nums[i]);
}
nums.forEach(function(num) {
  console.log(num);
});

The call is a method that is used to explicitly set the value of this in the greet function.

When a function is invoked as a method of an object, this keyword is set to the object that the method is called on. However, when a function is invoked directly, this keyword refers to the global object (or undefined in strict mode).

In the example code, the greet function does not have an object context to refer to, so this would normally be undefined. However, the call method is used to explicitly set the value of this to the person1 and person2 objects respectively. This allows the greet function to access the name property of each object and print out a personalized greeting for each person.

So, in short, the call method is used to explicitly set the value of this in a function call.

In the code above, you can see how explicit behavior is used in different scenarios such as type conversion, method invocation, variable scoping, conditional statements, and iteration. These behaviors require explicit instructions to occur and provide greater control over the behavior of the code.

Nominal In Javascript

In programming languages, nominal typing is a type system in which variables and values are explicitly named and categorized according to their data type or class.

Nominal typing requires explicit declarations of data types and enforces strong typing, meaning that variables cannot be automatically coerced or converted to different types.

In JavaScript, nominal typing is not as strict as in some other languages, such as Java or C#. However, JavaScript does have some features that can be considered nominal typing:

  1. Object constructors: JavaScript uses constructor functions to create objects with specific data types. For example, the Date constructor creates objects that represent dates and the RegExp constructor creates objects that represent regular expressions.

  2. Classes: Starting from ES6, JavaScript supports classes, which allow you to define blueprints for objects with specific data types. Classes can be seen as a more formalized way of using constructor functions.

  3. Type annotations: Although JavaScript does not enforce strong typing, you can use type annotations to explicitly declare the data type of a variable or function parameter. This can help catch type errors during development and make the code more self-documenting.

Structuring In Javascript

Structuring in Javascript refers to the process of organizing code into logical and reusable parts. Structuring can help make code easier to understand, maintain, and debug and also promote code reuse and modularity.

Some common techniques for structuring JavaScript code include:

  1. Functions: Functions are one of the fundamental building blocks of JavaScript code. They allow you to encapsulate logic and behavior into reusable units that can be called from other parts of your code.

  2. Objects: Objects in JavaScript provide a way to group related data and functionality into a single unit. Objects can be used to represent real-world entities or to encapsulate functionality that needs to be reused across different parts of your code.

  3. Modules: JavaScript modules are a way of encapsulating functionality into self-contained units of code that can be easily imported and used in other parts of your application. Modules provide a way to manage dependencies and reduce the risk of naming conflicts and other issues that can arise in larger codebases.

  4. Classes: JavaScript classes, introduced in ES6, provide a way to define blueprints for objects with shared behavior and properties. Classes can be seen as a way to encapsulate related functionality into reusable units and provide a more formalized way of using constructor functions.

  5. Promises: Promises in JavaScript provide a way to handle asynchronous operations in a structured and organized way. Promises allow you to chain together multiple asynchronous operations, handle errors, and avoid callback hell.

Here is an example of using some of these techniques for structuring JavaScript code:

// Define a function for adding two numbers
function addNumbers(num1, num2) {
  return num1 + num2;
}

// Define an object for representing a person
let person = {
  name: "John Smith",
  age: 30,
  email: "john.smith@example.com",
  getAge: function() {
    return this.age;
  }
};

// Define a module for performing math operations
let mathUtils = (function() {
  function multiplyNumbers(num1, num2) {
    return num1 * num2;
  }

  function divideNumbers(num1, num2) {
    return num1 / num2;
  }

  return {
    multiplyNumbers: multiplyNumbers,
    divideNumbers: divideNumbers
  };
})();

// Define a class for representing a car
class Car {
  constructor(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
  }

  getInfo() {
    return this.year + " " + this.make + " " + this.model;
  }
}

// Use a promise to fetch data from an API
fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.log(error));

By using these techniques and others, you can structure your JavaScript code in a way that promotes readability, maintainability, and code reuse, and helps you avoid common pitfalls and issues that can arise in large and complex codebases.

Duck Typing

Duck typing is a concept in programming that refers to the practice of determining the type or behavior of an object based on its properties and methods, rather than its explicit type. In other words, if an object looks like a duck, swims like a duck, and quacks like a duck, then it's a duck. This approach is often used in dynamically typed languages like JavaScript.

In JavaScript, duck typing allows you to write flexible and reusable code that can work with a wide range of objects, as long as they have the required properties and methods. For example, you might write a function that expects an object with a "name" property and a "sayHello" method:

function greet(obj) {
  console.log(`Hello, ${obj.name}!`);
  obj.sayHello();
}

const person = {
  name: 'Alice',
  sayHello() {
    console.log('Hi there!');
  }
};

const animal = {
  name: 'Duck',
  sayHello() {
    console.log('Quack!');
  }
};

greet(person); // logs "Hello, Alice!" and "Hi there!"
greet(animal); // logs "Hello, Duck!" and "

In the above example, the greet function takes an object obj as its parameter, and assumes that the object has a name property and a sayHello method. The person and animal objects are created with those properties and methods, so they can be passed to the greet function.

When greet(person) is called, the output is "Hello, Alice!" and "Hi there!" because person has a name property with the value 'Alice' and a sayHello method that logs "Hi there!".

Similarly, when greet(animal) is called, the output is "Hello, Duck!" and "Quack!" because animal has a name property with the value 'Duck' and a sayHello method that logs "Quack!".

Note that neither person nor animal are explicitly declared as a certain type (e.g. class or interface) - the greet function just assumes that they have the required properties and methods based on their structure. This is an example of duck typing in JavaScript.

This was a lot to takein for the day and I hope you have now understood these different and important terminologies in javascript and how you use the daily.

Please leave a comment if you found this post helpful:

For Day 5 we will be dealing with == vs === vs typeof in javascript. See you then: