Closed magicmatatjahu closed 3 years ago
Hey! You've labeled this issue as a Scope. Remember you can use the following command to inform about its progress:
/progress <percentage> [message]
or
/progress <percentage>
A mutiline message.
It supports **Markdown**.
/progress 40 We're still figuring out how to implement this. We have an idea but it is not yet confirmed it will work.
/progress 50
A few notes:
* We got this figured out :tada:
* We're going to use [this library](#link-to-website) to avoid losing time implementing this algorithm.
* We decided to go for the quickest solution and will improve it if we got time at the end of the cycle.
:weight_lifting_woman: See the progress on the Shape Up Dashboard.
Used the time to familiarize myself with C# and outlined some of the important features/syntaxes it has to offer for later references.
General keywords:
C# required syntax:
;
as end characters.Uses namespace
to wrap functionality, which can also be nested as deep as you want.
C# uses directive keyword using <<namespace>>;
however it is not required to use, since fully qualified names are also possible. You can also alias a namespace by using Project = PC.MyCompany.Project;
. To access the resources within alias namespaces they use the operator ::
i.e. forwpf::Point
where forwpf
is an alias for System.Windows
.
OBS
using
keyword is also used in statements similar to try/catch.
There are some requirements to use the directive keyword:
C# also supports external namespaces uses something called extern alias GridV1;
Are supported and delcares methods to be implemented in class or struct.
interface IEquatable<T>
{
bool Equals(T obj);
}
Both class
and struct
are supported, where struct
is objects are passed by value and objects of classes are passed by reference. Nested classes are supported.
//[access modifier] - [class] - [identifier]
public class Customer
{
// Fields, properties, methods and events go here...
}
Is done using the syntax class B: A {}
where A
is another class which B
inherits from.
Attributes, fields, variables are being used to describe the same thing. Declared in classes
Variables use special keywords such as:
T?
also called nullablesDeclared in class, struct or interface and supports the following modifiers (visibility modifiers excluded):
abstract
means derived class must implement method.async
performs asynchronous Task
s by await
ing them to be completed.ref
returns and locals are basicall a way to alias existing variables. unsafe
denotes an unsafe context, used to enable pointers.To pass arguments by reference C# uses either out or ref. The difference between the two is:
ref tells the compiler that the object is initialized before entering the function, while out tells the compiler that the object will be initialized inside the function. It is required when using out
that it is initialized within the method.
So while ref is two-ways, out is out-only.
Two types of getter and setters are available Automatic Properties and the normal encapsulation such as:
private string email;
public string Email
{
get
{
return email;
}
set {
this.email = value;
}
}
Annotations, also called attributes in C#, can be placed on most declarations to add metadata. Attributes can have 3 types of parameters:
... positional, unnamed, or named. Any positional parameters must be specified in a certain order and cannot be omitted. Named parameters are optional and can be specified in any order. Positional parameters are specified first.
This means the following are equivalent:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
Multiple attributes can be described as the following example for parameters:
using System.Runtime.InteropServices;
void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }
They can also be targeted to certain targets using the form:
[target : attribute-list]
C# is a strongly typed language, beside the built in types provides the following type variants:
(string, int, double)
to bundle values./progress 5 Finished research regarding C#, next up C++.
Used the time to familiarize myself with C++ and outlined some of the important features/syntaxes it has to offer for later references.
General keywords:
C++ required syntax:
;
as end characters.OBS I have not consequently defined (sometimes I have when I've noticed it) which version of C++ syntaxs are added.
header
filesC++ uses .h
files for declarations while the implementation recide in the .cpp
file. Example
// my_class.h
namespace N
{
class my_class
{
public:
void do_something();
};
}
// my_class.cpp
#include "my_class.h" // header in local directory
#include <iostream> // header in standard library
using namespace N;
using namespace std;
void my_class::do_something()
{
cout << "Doing something!" << endl;
}
Although some inlines are possible to do.
Uses namespace to wrap functionality, which can also be nested as deep as you want.
namespace namespace_name {
// code declarations
}
Namespace content can be accessed using scope operator ::
.
C++ 20 have introduced something called module, import and export however it is still experimental so it will be excluded.
C++ uses the following syntax to include functionaliaty from other files:
#include "path-spec"
#include <path-spec>
The angle bracket are for including external (outside project) while the quoted inherits this after trying to search for it locally in the project first.
Is not directly supported, however methods can be defined using the keyword vitual
in classes. To declare a method to be pure virtual
which MUST be implemented by sub classes has the syntax = 0;
:
virtual double getVolume() = 0;
If you want to define it as optional leave out = 0;
virtual double getVolume();
Supports both normal class
es and struct
s. Some key differences
Members of a class are private by default and members of a struct are public by default.
When deriving a struct from a class/struct, default access-specifier for a base class/struct is public. And when deriving a class, default access specifier is private.
Classes has the syntax:
[template-spec]
class [ms-decl-spec] [tag [: base-list ]]
{
member-list
} [declarators];
Where template spec are template specifications, ms-decl-spec
storage-class specification, tag
is the name of the class (if ommited anonymous class is define), base-list
class or struct to inherit from, member-list
Class Member Overview, declarators
can be used to declare one or more instances of the class.
It is possible to overload operations such as +
, ==
for classes, read more here.
Structs has the syntax
[template-spec]
struct [ms-decl-spec] [tag [: base-list ]]
{
member-list
} [declarators];
The definitions for struct is the same as for class
.
Single and multi inheritance are supported.
class Derived : [virtual] [access-specifier] Base1
[ ,[virtual] [access-specifier] Base2, . . . ]
{
// member list
};
It is possible to declare visibility to the base class i.e. what is accessible by the derived class.
If multiple base classes are used some conditions are applied. The order of initialization by constructor i.e. if you want one base class constructor to be called first it should be first in the list of base classes. The same is applied to destructors just in reverse order.
Given two base classes has same methods and a derived class inherit from both one has to declare calls such as:
class C : public A, public B {};
C *pc = new C;
pc->B::a();
Called variables in C++.
Keywords:
User-defined literals where introduced in C++ 11 and allows the definition of values with custom litreals such as auto d = 42.0_km
C++ are notorish for its pointers and memory leaks. Normal pointers are called raw pointers and uses the syntax:
int* p = nullptr; // declare pointer and initialize it
// so that it doesn't store a random address
int i = 5;
p = &i; // assign pointer to address of object
int j = *p; // dereference p to retrieve the value at its address
However in modern C++ smart pointers are introduced so programmers dont have to worry about memory leaks.
Called functions in C++ and has the syntax:
declarations return-type name ( ... parameters) {
statements
}
Optional function declarations
:
constexpr
return value of function is a constant.inline
. expression
are true.final
and override
. virtual
function can be overridden, override
function in derived class is overriding vitual function and final
declare function to not be overridden any further.const
or volatile
.No special encapsulation such as C# offers - Wrapping variables are ofcourse still supported.
are a type of anonymous function object which can be created where needed and has the syntax:
[capture-closure] ( ... parameters ) specifiers exception -> return-type {
body
}
capture-close
are used to access outside variables within the body
of the lambda function. parameters
optionally multiple function parameters. specifiers
optional keywords such as mutable
, constexpr
and consteval
. exception
provides the definition of dynamic exception specification. return-type
optionally the type of value returned by the function. body
the function implementation.
C++ does not have anything related to annotations.
If you want to serialize and deserialize objects into/from JSON one could implement and provide the metadata themself so in the end you could endup with something like:
Dog dog;
dog.color = "green";
dog.barkType = "whaf";
dog.weight = 30;
Json::Value jsonDog = toJson(dog); // produces {"color":"green", "barkType":"whaf", "weight": 30}
auto dog2 = fromJson<Dog>(jsonDog);
std::cout << std::boolalpha << (dog == dog2) << std::endl; // pass the test, both dog are equal!
Visibility can be defined with a multiline approach such as:
protected:
int width;
int height;
C++ is a strongly typed language, beside the built in types provides the following type variants:
/progress 10 Finished C++ research, next to do is JavaScript.
JS (JavaScript) are an interpreted language meaning that JS code are interpreted at run time. Most browsers however uses a JIT compiler which compiles JS to bytecode before its being executed.
Just to have a quick rundown of the JS module formats which are CommonJS (CJS), Asynchronous Module Definition (AMD), Universal Module Definition (UMD) and then there is native JS also refered to as ECMAScript where the implemented and used versions are ES5 (ECMAScript 5 (2009)) and ES6 (ECMAScript 2015). ES6 is however fully backward compatible with ES5. ES6 is supported in most browsers.
If you have to use the code in Node.JS and write in any other module formats a transpiler has to be used to convert it into CJS which is what Node.JS understands.
Strict mode is something that can be included by adding 'use strict';
which enables a stricker syntax validation, increased performance and some silent errors will be thrown.
I will be giving 2 examples for modules and imports in CJS and ES6 formats since these are the most used (by us).
ES6 uses export
keyword while CJS uses module.exports or exports
keyword.
export default function doSomething(n) {
// do something
}
export function doSomething(n) {
// do something
}
//exporting
module.exports = function doSomething(n) {
// do something
}
exports.doSomething = (n) {
// do something
}
ES6 introduces an import
keyword while CJS uses require
keyword.
// Everything
import module from 'module_name'
//Parts of the module
import { doSomething } from 'module_name'
// Everything
var module = require('module_name');
//Parts of the module
var { doSomething } = require('module_name');
Interfaces are not support and there is no way to declare a class must implement some function(s).
ES6 introduced the class
and extend
keyword to JS built upon prototypes. Just to quickly mention prototypes, it is the old way of defining inheritance between objects (and still needed for Internet Explorer solutions).
Extend does introduce inheritance however but multiple inheritance is not supported, therefore mix-ins where introduced.
Static methods and properties are also supported and works the same way as in other languages where the class does not need to be initialized to access it.
class Square extends SomeBaseClass {
constructor(length) {
// Here, it calls the parent class' constructor with lengths
super(length, length);
}
//Static property
static displayName = "Square";
//Encapsulation
get area() {
return this.height * this.width;
}
}
Mix-ins example:
let calculatorMixin = Base => class extends Base {
calc() { }
};
let randomizerMixin = Base => class extends Base {
randomize() { }
};
class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }
It is possible to declare functions as get
and set
property methods which allows for something like the following:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
Attributes are stated with either const
, let
or var
which affects the scope of the variable as well as what is allowed to change.
Not possible to re-declare variables.
'use strict';
let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
If let
is used in a global scope its not created as a property on the global object.
let bar = "Bar"; // globally scoped
console.log(window.bar); // undefined
Accessing a let
variable before initialized throws a reference error.
console.log(foo); // ReferenceError
let foo = "Foo";
console.log(foo); // Foo
Can be re-declared without any issues
'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.
If var
is used in a global scope it is created as a property on the global object.
var foo = "Foo"; // globally scoped
console.log(window.foo); // Foo
Accessing a var
that is not yet initialized just returns undefined.
console.log(foo); // undefined
var foo = "Foo";
console.log(foo); // Foo
Inherits all the same properties as let
with the exception of it cannot be reassigned.
const PI = 3.141592653589793;
PI = 3.14; // This will give an error
PI = PI + 10; // This will also give an error
In JavaScript methods are called functions and are First-class functions meaning they are treated as any other variables such as:
const sayHello = function() {
return "Hello, ";
}
function greeting(helloMessage, name) {
console.log(helloMessage() + name);
}
// Pass `sayHello` as an argument to `greeting` function
greeting(sayHello, "JavaScript!");
When a function is returned by another function that first functions is called a Higher-Order function. The returned function can be invoked directly when returned as so:
function sayHello() {
return function() {
console.log("Hello!");
}
}
sayHello()();
There is no annotations/metadata supported in the JS.
There are no visibility modifiers supported in prior ES6. However scope introduces some sort of visibility such as the following:
function Person(name) {
let age = 20; // this is private
this.name = name; // this is public
this.greet = function () {
// here we can access both name and age
console.log(`name: ${this.name}, age: ${age}`);
};
}
let joe = new Person('Joe');
joe.greet();
// here we can access name but not age
ES6 introduced private visibility with the following class syntax (note not supported by all browsers/Node.JS and versions):
class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
JS is a loosely typed language meaning although variables have types underneath those types can be changed on the fly.
let foo = 42; // foo is now a number
foo = 'bar'; // foo is now a string
foo = true; // foo is now a boolean
The data types includes:
/progress 25 finished Javascript, next Haskell.
General keywords:
static
: A static field belongs to the class. Thus, no matter how many objects is created, there will only exist one field located in the class, and the value of that field is the same, no matter from which object it is accessed.final
: A final field cannot have its value changed, once assigned. Similar to readonly
field in other languages.abstract
: A method with no definition must be declared as abstract and the class containing it must be declared as abstract. Abstract classes cannot be instantiated. Abstract methods must be implemented in the sub classes. The abstract keyword cannot be used with variables or constructors. Abstract class isn't required to have an abstract method at all.transient
: The transient keyword in Java is used to avoid serialization. If any object of a data structure is defined as a transient, then it will not be serialized (serialization is the process of converting an object into a byte stream).Java required syntax:
;
as end operation.Packages are used in Java in order to prevent naming conflicts, to control access, to make searching/locating and usage of classes, interfaces, enumerations and annotations easier, etc.
A Package can be defined as a grouping of related types (classes, interfaces, enumerations and annotations) providing access protection and namespace management.
Conventions for packages in Java:
com.somepackage
where are a top level package named com
with a subpackage inside called somepackage
. Example of package's declaration:
package com.somepackage;
public class SomeClass {}
Java has an import
statement that allows you to import an entire package, or use only certain classes and interfaces defined in the package.
The general form of import statement is:
import com.somepackage.ClassName; // To import a certain class only
import com.somepackage.*; // To import the whole package
public class SomeClass {}
To describe...
A Java class can contain the following building blocks:
Java supports overloading of constructors, throwing exception in constructor, calling a constructor from an another constructor etc. More info and examples are here
In Java inheritance is declared using the extends
keyword:
class Car extends Vehicle {}
Java doesn’t allow multiple inheritance to avoid the ambiguity caused by it.
final class Car {}
A final
class cannot be extended. In other words, you cannot inherit from a final
class in Java.
A Java interface
is a bit like a Java class, except a Java interface can only contain method signatures and fields. A Java interface is not intended to contain implementations of the methods, only the signature (name, parameters and exceptions) of the method. However, it is possible to provide default implememntations of a method in a Java interface, to make the implementation of the interface easier for classes implementing the interface.
Class can implements interface by syntax:
class Car implements Engine, Tires {}
Implementation of multiple interfaces is allowed.
Properties in interface is similar to static
fields in class (it can be used). Method needs to be implemented by some class before accesing. Method can be also static
and this modifier treats method as callable outside of implmentation in class.
Interfaces in Java have a lot of features, so better will be read this document than describing them here.
The Java method signature looks like:
The void
return type states that a method is a procedure.
Can be declared in class or in interface and supports the following modifiers:
abstract
: derived class must implement method.A Java method parameter can be declared as final
, just like a variable. The value of a final parameter cannot be changed. That is, if the parameter is a reference to an object, the reference cannot be changed, but values inside the object can still be changed. Example:
public void writeText(final String text1, final String text2) {
System.out.print(text1);
System.out.print(text2);
}
text1
and text2
parameters cannot be reassigned inside the method.
If an error occurs inside a method, the method may throw an exception. Exceptions have to be declared in the method declaration throws {Exception}
:
public String ret(String _string) throws MyException {
if(_string == null) {
throw new MyException("_string was null");
}
return _string;
}
Encapsulation in Java can be done using setXXX
and getXXX
methods for properties in class. Example:
public class SomeClass {
private int age;
public int getAge() {
return age;
}
public void setAge(int newAge) {
age = newAge;
}
}
are a type of anonymous function which can be created where needed and has the syntax:
<function's parameters> -> <body of function>
Example:
(Integer x, Long y) -> System.out.println(x * y)
Java method cannot be async
by modifier and also the word await
cannot be used inside it. However, there are implementations of asynchronicity in standard libraries, which are based on OOP.
Java annotations are used to provide metadata for Java code. Being metadata, Java annotations do not directly affect the execution of code, although some types of annotations can actually be used for that purpose.
Java annotations are typically used for the following purposes:
Annotation has form:
@<AnnotationName>(...parameters) target{class, method, property}
Example of using the annotation:
@SomeAnnotation(
name="Jakob",
age=37,
)
public class SomeClass {}
More info, how to create annotations and used them is here.
package
modifier): A variable or method declared without any access control modifier is available to any other class in the same package. The fields in an interface are implicitly public static final
and the methods in an interface are by default public
.public
: A class, method, constructor, interface, etc. declared public can be accessed from any other class. Therefore, fields, methods, blocks declared inside a public class can be accessed from any class. Class and interfaces can be declared as public.protected
: Variables, methods, and constructors, which are declared protected in a superclass can be accessed only by the subclasses in other package or any class within the package of the protected members' class. Class and interfaces cannot be declared as protected, also methods and fields in a interface cannot be declared protected.private
: Methods, variables, and constructors that are declared private can only be accessed within the declared class itself. Class and interfaces cannot be declared as private.Java types can be divided to two kind:
More info is here.
Beside the built in types provides the following type variants:
NOTE: Java has also special keywords for multithreading programming like
volatile
etc, but there it isn't explained. For more information, please read this.
/progress 30 finished Java, next Python.
Resources:
Python required syntax:
Modules and packages in Python allows to hierarchy code inside project. Difference between modules and packages can be described by describing packages:
Packages allow for a hierarchical structuring of the module namespace using dot notation. In the same way that modules help avoid collisions between global variable names, packages help avoid collisions between module names.
Modules are created by corresponding .py
filenames and packages by corresponding directories names. So in hierarchy like:
dir -|
|- module1.py
|- subdir -|
|- module2.py
dir
and dir.subdir
are packages and module1
and module2
are modules.
More info about modules/packages is here.
Module contents are made available to the caller with the import statement. The import statement takes many different forms, shown below (with examples):
# FOR MODULES
# here `import` does not make the module contents directly accessible to the caller. Each module has its own private `symbol table`, which serves as the global `symbol table` for all objects defined in the module. Thus, a module creates a separate namespace.
import <module_name>[, <module_name> ...]
import mod, anothermod
mod.s # access to objects from `mod` module by `.` char - a module creates a separate namespace
from <module_name> import <name(s)>
from mod import s, foo
# This will place the names of all objects from <module_name> into the local symbol table, with the exception of any that begin with the underscore (_) character.
from <module_name> import *
s # this same as mod.s
from <module_name> import <name> as <alt_name>[, <name> as <alt_name> …]
from mod import s as string, a as alist
string # this same as mod.s
import <module_name> as <alt_name>
import mod as my_module
my_module.s # this same as mod.s
# module contents can be imported from within a function definition. In that case, the import does not occur until the function is called
def bar():
from mod import foo
foo('corge')
# FOR PACKAGES
# Packages very similar to modules but there we import modules as single objects
from <package_name> import <modules_name>[, <module_name> ...]
from <package_name> import <module_name> as <alt_name>
from pkg import mod2 as quux
from pkg.mod3 import *
More info about imports is here.
The usual syntax for defining a Python function is as follows:
def <function_name>([<parameters>]):
<statement(s)>
where:
def
- the keyword that informs Python that a function is being defined<statement(s)>
- a block of valid Python statementsTo Python's functions we can also pass arguments by Keyword Arguments
, like:
some_function(qty=6, item='bananas', price=1.74)
More info about functions in Python is here. There is described Positional Arguments
etc. very interesting features.
All class definitions start with the class keyword, which is followed by the name of the class and a colon. Any code that is indented below the class definition is considered part of the class’s body"
class Person:
pass
The body of the Person
class consists of a single statement: the pass
keyword. pass is often used as a placeholder indicating where code will eventually go. It allows you to run this code without Python throwing an error.
class Person:
# Class attribute/fields
sex = "m"
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, sound):
return f"{self.name} says {sound}"
# initialization of class
person = Person("John", 33)
__init__
function is a constructor of class and self
represents created instance (like this
in other languages).
Inheritance in Python is make by correlation between classes parent class -> child class
. To create a child class, new class should be created with its own name and with the name of the parent class in parentheses. Example:
class Woman(Person):
# Override `speak` method - change the returned string
def speak(self, sound):
return f"{self.name} woman says: {sound}"
In python we can access the parent class from inside a method of a child class by using super()
:
class Woman(Person):
def speak(self, sound="Hello"):
return super().speak(sound)
Interfaces in Python are handled differently than in most other languages, and they can vary in their design complexity. It is created like child class
, so in example:
class Woman(Person):
pass
Person
class is an interface.
More info about it (with complex examples) is here
Instance methods are functions that are defined inside a class and can only be called from an instance of that class. Just like __init__
, an instance method’s first parameter is always self.
class Person:
# Class attribute/fields
sex = "m"
def __init__(self, name, age):
self.name = name
self.age = age
# Instance method
def description(self):
return f"{self.name} is {self.age} years old"
# Another instance method
def speak(self, sound):
return f"{self.name} says {sound}"
# invokation of method
miles = Person("Miles", 56)
miles.description()
Methods like __init__
and __str__
(called when used is print
function on given instance) are called dunder methods
because they begin and end with double underscores. There are many dunder methods that can be used to customize classes in Python. Examples and usage of dunder methods can be found here.
Python hasn't annotations like Java, but decorators. It doesn't collect metadata (but they can - by custom logic inside decorator - very similar to decorators in Typescript), but wraps a function, modifying its behavior. Example:
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_something():
print("Hello!")
say_something()
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.
Decorators works also for classes and there it also wraps a class, modifying its behavior. Example:
from dataclasses import dataclass
@dataclass
class DataClassCard:
rank: str
suit: str
We should investigate more deeper dataclasses
package, because it'll help us to create models for Python (like in QuickType). More info is here.
More info about decorators and their behaviours is here.
Python (from v3.6) has a type system. It's very similar to TS type system so I don't want to described it here. More info is here.
Syntax for typings:
value: Type
Python has no such visibility restrictions. All attributes and methods are visible to everyone. Anyone who wishes to use knowledge about the implementation of an object can do so. That can result in more efficient code. It can also result in a crash if the implementation changes. The language does nothing to prohibit programmers from "breaking encapsulation."
However, Python does provide name mangling
to help hide names in classes. If you begin the name of an attribute of a class with two underscores, and you don't end it with any underscores, it is automatically rewritten to include the class name. Here's an example:
class XX:
def __init__(self):
self.__x=0
z=XX()
dir(z) # ['_XX__x']
The attribute __x
in class XX
was renamed to _XX__x
. It doesn't prevent anyone from accessing it, but it does make it more unpleasant, which should serve to discourage casual use. Just as important, this keeps the attributes used privately by one class separate from those used by another.
Example | Data Type |
---|---|
x = "Hello World" | str |
x = 20 | int |
x = 20.5 | float |
x = 1j | complex |
x = ["apple", "banana", "cherry"] | list |
x = ("apple", "banana", "cherry") | tuple |
x = range(6) | range |
x = {"name" : "John", "age" : 36} | dict |
x = {"apple", "banana", "cherry"} | set |
x = frozenset({"apple", "banana", "cherry"}) | frozenset |
x = True | bool |
x = b"Hello" | bytes |
x = bytearray(5) | bytearray |
x = memoryview(bytes(5)) | memoryview |
def say_hello() | function (first-class objects) |
x = Foo() | class |
The other builded (composite/based on function) types could be find here.
Haskell is a functional programming language using lazy evaluation with a mathematical syntax such as:
f :: int -> int
f x = x^2 + 3
-- which resembles a mathematical function
f(x) = x^2 + 3
"Literature":
Constraints:
main
function with the type main :: IO ()
. IO
::
can be read as has type
and is also used in type casting.All functions names must start with a lowercaseletter or “_”. It is a syntax error otherwise.
Haskell (as is described on beginning of investigation) is a functional language and everything is denoted as an expression, hence a Module can be called as a collection of similar or related types of functions.
More info about modules and imports is here. Imports private entities for testing - https://stackoverflow.com/a/14379426/6803886.
Syntax for Module:
module modid [exports] where body
where:
modid
is a name of moduleexports
is a list of exported entities (enclosed in round parentheses)where
is a syntax keyword and must be defined before body
body
is a body of module (code of entities)Example:
module Queue( module Stack(..), enqueue, dequeue ) where
import Stack
Above Queue
module exports Stack
module (which is imported) and enqueue
, dequeue
entities/functions. import Stack
is a body of module.
Very important:
Stack
names the class but not the class methods.Stack(f1,…,fn)
, names the class and some or all of its methods.Stack(..)
names the class and all its methods that are in scope (whether qualified or not).Syntax for imports:
import [qualified] modid [as modid] [impspec]
where impspec is:
( import1 , … , importn [ , ] ) where n >= 0
hiding ( import1 , … , importn [ , ] ) where n >= 0
The entities exported by a module may be brought into scope in another module with an import
declaration at the beginning of the module. The import
declaration names the module to be imported and optionally specifies the entities to be imported. A single module may be imported by more than one import
declaration. Imported names serve as top level declarations: they scope over the entire body of the module but may be shadowed by local non-top-level bindings.
The effect of multiple import
declarations is strictly cumulative: an entity is in scope if it is imported by any of the import declarations in a module. The ordering of import
declarations is irrelevant.
Lexically, the terminal symbols as
, qualified
and hiding
are each a varid rather than a reservedid. They have special significance only in the context of an import declaration; they may also be used as variables.
qualified
keyword means that imported entities must by preceded by name of imported module like {moduleName}.{entity}
.
hiding
hides entities from imported module.
as
keyword is a alias for imported module.
Module A
exports x
and y
:
Import declaration | Names brought into scope |
---|---|
import A | x, y, A.x, A.y |
import A() | (nothing) |
import A(x) | x, A.x |
import qualified A | A.x, A.y |
import qualified A() | (nothing) |
import qualified A(x) | A.x |
import A hiding () | x, y, A.x, A.y |
import A hiding (x) | y, A.y |
import qualified A hiding () | A.x, A.y |
import qualified A hiding (x) | A.y |
import A as B | x, y, B.x, B.y |
import A as B(x) | x, B.x |
import qualified A as B | B.x, B.y |
Haskell hasn't got interface
keyword, however class
syntax works in similar way (in comparison to Java's interface
).
Haskell has also class
keyword but classes in Haskell works diffrerentially with comparison Java or C++. They allow us to declare which types are instances of which class, and to provide definitions of the overloaded operations/functions
associated with a class - something like a interfaces rather than class in e.g. Java - classes are like generic interfaces.
For example:
class Eq a where
(==) :: a -> a -> Bool
Here Eq
is the name of the class being defined, and ==
is the single operation (function) in the class. This declaration may be read "a" type a is an instance of the class "Eq" if there is an (overloaded) operation ==, of the appropriate type, defined on it.
.
And then we have a instance
s (implementation of class) of Eq
class:
instance Eq Integer where
x == y = x `integerEq` y
instance Eq Float where
x == y = x `floatEq` y
Methods in Haskell inside the class works in this same way as normal functions but can handle (extend) context of class: a
.
class Eq a where
(==) :: a -> a -> Bool
instance Eq Integer where
x == y = x `integerEq` y
==
is a method, the function integerEq
happens to be the primitive function that compares integers for equality, but in general any valid expression is allowed on the right-hand side, just as for any other function definition. The overall declaration is essentially saying: The type "Integer" is an instance of the class "Eq:, and here is the definition of the method corresponding to the operation ==
.
Haskell also supports a notion of class extension. For example, we can define a class Ord
which inherits all of the operations in Eq
, but in addition has a set of itself functions:
class (Eq a) => Ord a where
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
In the context: Eq
is a superclass of Ord
(conversely, Ord
is a subclass of Eq
), and any type which is an instance of Ord
must also be an instance of Eq
(like in Java or other OOP languages).
Haskell also permits multiple inheritance, since classes may have more than one superclass. For example, the declaration:
class (Eq a, Show a) => C a where ...
creates a class C
which inherits operations from both Eq
and Show
.
In Haskell we cannot define attributes inside class, we must make first data
(something like struct
in C/C++) type and then implements (create instance
) class for this type, like:
class Person a where
firstName :: a -> String
lastName :: a -> String
age :: a -> Int
getFullName :: a -> String
data Employee = Employee
{ employeeFirstName :: String
, employeeLastName :: String
, employeeAge :: Int
, company :: String
, email :: String
, salary :: Int
}
instance Person Employee where
firstName = employeeFirstName
lastName = employeeLastName
age = employeeAge
getFullName e = employeeFirstName e ++ " " ++ employeeLastName e
Haskell hasn't encapsulation inside class (setter/getter).
Called functions in Haskell are defined with a type expression before the actual function definition are expressed.
The type expression is declared on the form:
function-name :: parameter1-type -> parameter2-type -> ... -> return-type
The function is defined on the form:
function-name parameter1 parameter2 ... = definition
Functions are generatlly called using a prefix notation:
return-value = function-name argument1 argument2 ...
However some functions such as +
are considered an infix functions and can be called using 1 + 2
which is the same as the prefix notation (+) 1 2
. Normal prefix functions can use infix notation by wrapping the function in `somefunction`.
List comprehension
is way to generate certain values i.e. below code will generate a list of squared values for values between 1 and 10. It can consists of generators
, guards
, local bindings
, and targets
.
squares = [x * x | x <- [1..10]]
Some list operators.
++
appends two lists together i.e. [x]++[y]
is the same as [x, y]
:
conses an element onto a list i.e. y:x:[]
is the same as [y, x]
Pattern matching is a technique which allows one to specify multiple declarations based on parameter values. Pattern matching are matched from top to bottom. An example of such can be seen in the factorial implementation below:
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n-1)
_
works like a wildcard and matches any value.[]
or (min, max)
. Example with a isEmpty
function:isEmpty (1:_) = "List is not empty!"
isEmpty [] = "List is empty!"
x:y:xs
"This is a list with at least 2 elements. We will call the first and second elements of this list x and y. The remaining sublist, which we will call xs may be empty or non-empty."variable-name@
infront such as ls@(x:xs)
will give you access to the entire list/string through ls
.Similar to pattern matching guarding is a bit different in how it matches expressions and similar to if-else statements. Guards are matched from top to bottom.
fact :: Integer -> Integer
fact n | n == 0 = 1
| n /= 0 = n * fact (n-1)
otherwise
keyword can be used to describe a result for all other values then the ones that have been defined.
Where
and Let In
where and let do the same but its syntax is different:
rootsWhere :: (Float, Float, Float) -> (Float, Float)
rootsLet :: (Float, Float, Float) -> (Float, Float)
rootsWhere (a,b,c) =
(x1, x2)
where
x1 = e + sqrt d / (2 * a)
x2 = e - sqrt d / (2 * a)
d = b * b - 4 * a * c
e = - b / (2 * a)
rootsLet (a,b,c) =
let d = b * b - 4 * a * c
e = - b / (2 * a)
x1 = e + sqrt d / (2 * a)
x2 = e - sqrt d / (2 * a)
in (x1, x2)
main = do
putStrLn "The roots of our Polynomial equation are:"
print (rootsWhere(1,-8,6))
print (rootsLet(1,-8,6))
It is also possible to use a case
statement similar to patern matching.
describeList :: [a] -> String
describeList xs = "The list is " ++ case xs of [] -> "empty."
[x] -> "a singleton list."
xs -> "a longer list."
otherwise
keyword can be used to describe a result for all other values then the ones that have been defined.
Haskell hasn't annotations like in Java or C#.
Visibility is not something that can explicit be sat as other languages such as private
, protected
etc, instead its an inherit property based on the context of the code.
Every value has a strict type.
Structured types:
[...types]
)(Int,Int)
)/progress 35 finished Python, I'm helping Jonas in investigation of Haskell.
/progress 50 finished Haskell
Resources:
Go programs are organized into packages. A package is a collection of source files in the same directory that are compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package.
A repository contains one or more modules. A module is a collection of related Go packages that are released together. A Go repository typically contains only one module, located at the root of the repository. A file named go.mod
there declares the module path: the import path prefix for all packages within the module. The module contains the packages in the directory containing its go.mod
file as well as subdirectories of that directory, up to the next subdirectory containing another go.mod
file (if any).
In GoLang we import packages using import
statement:
import "fmt"
func main() {
fmt.Println("Go is great!")
}
In importing like in above example import "fmt"
we treat the package name (fmt
) as alias to exported entities from fmt
package - we can use Println
function writing fmt.Println
.
When importing multiple packages, its most common to wrap them with import ( ) rather than having to type out import everytime:
import (
"fmt"
"bytes"
)
We can use also custom aliases for imported packages:
import (
f "fmt"
"bytes"
)
func main() {
f.Println("Go is great!")
}
For more information about imports (especially dot
and blank
imports) check this document.
Unlike traditional Object-Oriented Programming, Go does not have class-object architecture. Rather, GoLang have structures that hold complex data structures.
A struct
type is nothing but a schema containing the blueprint of a data a structure will hold:
type StructName struct {
// exported
Field1 fieldType1
// not exported
field2 fieldType2
}
GoLang's structs also support as field function:
type StructName struct {
Function func (string) string
}
More info about structs (promoted fields, anonymous fields etc.) is here.
Go programming language supports special types of functions called methods. In method declaration syntax, a "receiver" is present to represent the container of the function. This receiver can be used to call a function using "." operator. Syntax:
func (receiver receiver_data_type) function_name([parameter list] = [parameter_name parameter_type, ...]) [return_type]{
/* function body*/
}
Example:
/* define a circle */
type Circle struct {
x,y,radius float64
}
/* define a method for circle */
func(circle Circle) area() float64 {
return math.Pi * circle.radius * circle.radius
}
func main(){
circle := Circle{x:0, y:0, radius:5}
fmt.Printf("Circle area: %f", circle.area())
}
GoLang's struct hasn't native constructor like in Java. Common practice in GoLang's community is creating function with New*
suffix for creating instance of given type:
/* define a circle */
type Circle struct {
x,y,radius float64
}
func NewCircle(x,y,radius float64) Circle {
return Circle{x,y,radius}
}
There aren't inheritance like in Java or C# (by extend
keyword syntax). However in GoLang we can use compisition and use anonymous fields in struct definition, like in example:
// declaring first
// base struct
type first struct{
// declaring struct variable
base_one string
}
// declaring second
// base struct
type second struct{
// declaring struct variable
base_two string
}
// function to return
// first struct variable
func (f first) printBase1() string{
// returns a string
// of first struct
return f.base_one
}
// function to return
// second struct variable
func (s second) printBase2() string{
// returns a string
// of first struct
return s.base_two
}
// child struct which
// embeds (inherits) both base structs
type child struct{
// anonymous fields,
// struct embedding
// of multiple structs
first
second
}
More info about inheritance like in OOP languages is here.
GoLang haven't native getters and setters, but there is possibility to create for each field in struct coresponding getter and setter:
/* define a circle */
type Circle struct {
x float64
}
/* Getter */
func(circle Circle) GetX() float64 {
return circle.x
}
/* Setter */
func(circle Circle) SetX(x float64) {
circle.x = x
}
There aren't annotations like in Java or C#. However GoLang has tags
inside structs.
Go struct tags
are annotations that appear after the type in a Go struct declaration. Each tag is composed of short strings associated with some corresponding value:
type User struct {
Name string `example:"name"`
}
example:"name"
is a tag.
Go tags
is commonly used to define coresponding json/yaml definition:
type User struct {
Name string `json:"name"`
Password string `json:"password"`
CreatedAt time.Time `json:"createdAt"`
}
Reflections from the reflect
package are used to read data from tags and process them.
Unlike other program languages like Java that use access modifiers such as public
, private
, or protected
to specify scope, Go determines if an item is exported and unexported through how it is declared. Exporting an item in this case makes it visible outside the current package. If it’s not exported, it is only visible and usable from within the package it was defined.
This external visibility is controlled by capitalizing the first letter of the item declared. All declarations, such as Types, Variables, Constants, Functions, etc., that start with a capital letter are visible outside the current package.
// exported
var Greeting string
// not exported
func hello(name string) string {
return fmt.Sprintf(Greeting, name)
}
In Go language, the type is divided into four categories which are as follows:
/progress 60 finished Go
The following examples are only pure examples (mocks) and most likely our implementation won't look like this. They are used to show language differences and how they could be implemented as template using React.
{
type: 'object',
properties: {
displayName: {
type: 'string'
},
email: {
type: 'string',
format: 'email'
}
}
}
<Namespace name="temp">
<Class name={commonModel.uid()}>
{
Object.entries(commonModel.properties()).map((propertyName, property) => {
return (
<Property
property={property}
private
name={propertyName}
>
<Metadata>
[Serializable]
</Metadata>
<SetAccessor public />
<GetAccessor public />
</Property>
)
})
}
{/* Custom constructor beside default constructor */}
<Constructor>
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
this.displayName = displayName;
this.email = email;
</Body>
</Constructor>
{/* Add some custom method */}
<Method public name="someMethod" returnType="bool">
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
return email == displayName;
</Body>
</Method>
</Class>
</Namespace>
Must have to be implemented:
<Namespace>
, <Import>
(or <Imports>
/<Using>
), <Class>
, <Constructor>
, <Interface>
, <Property>
, <Method>
, <Argument>
(or <Parameter>
), <Enum>
, <Annotation>
(or <Metadata>
), <Setter>
(or <SetAccessor>
), <Getter>
(or <GetAccessor>
), <Body>
. Getter and Setter could be include in <Accessors>
component. String inside Method component could be treated as Body component.
Nice to have:
<Struct>
, <Lambda>
, <Extern>
.
<Class name={commonModel.uid()}>
{
Object.entries(commonModel.properties()).map((propertyName, property) => {
return (
<>
<Property
property={property}
private
name={propertyName}
>
<Annotation name="JsonProperty" value="email" />
</Property>
<SetAccessor public property={property} name={propertyName} />
<GetAccessor public property={property} name={propertyName} />
</>
)
})
}
{/* Custom constructor beside default constructor */}
<Constructor>
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
this.displayName = displayName;
this.email = email;
</Body>
</Constructor>
{/* Add some custom method */}
<Method public name="someMethod" returnType="boolean">
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
return email == displayName;
</Body>
</Method>
</Class>
Must have to be implemented:
<Package>
, <Import>
(or <Imports>
), <Class>
, <Constructor>
, <Interface>
, <Property>
, <Method>
, <Argument>
(as parameter in method/constructor), <Enum>
, <Annotation>
, <Setter>
(or <SetAccessor>
), <Getter>
(or <GetAccessor>
), <Body>
. Getter and Setter could be include in <Accessors>
component. String inside Method component could be treated as Body component.
Nice to have:
<Lambda>
, <Record>
.
<Class name={commonModel.uid()}>
<Decorator name="dataclass" />
{
Object.entries(commonModel.properties()).map((propertyName, property) => {
return (
<Property
property={property}
name={propertyName}
/>
)
})
}
{/* Class don't need constructor when it using dataclass decorator */}
{/* Add some custom method */}
<Method name="someMethod" returnType="bool">
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
return email == displayName;
</Body>
</Method>
</Class>
Must have to be implemented:
<Import>
(or <Imports>
), <Class>
, <Constructor>
(dunder __init__
method), <Property>
, <Method>
, <Argument>
(as parameter in method/constructor), <Decorator>
, <Setter>
(or <SetAccessor>
), <Getter>
(or <GetAccessor>
), <Function>
, <Body>
. Getter and Setter could be include in <Accessors>
component. String inside Method component could be treated as Body component. <Enum>
(from enum
package like class Days(enum.Enum)
) - more info is here,
Nice to have:
<Interface>
(this same as <Class>
in Python case), <DunderMethod>
(or maybe use normal <Method>
?).
<Class name={commonModel.uid()}>
<Constructor>
<Argument name="displayName" />
<Argument name="email" />
<Body>
this.displayName = displayName;
this.email = email;
</Body>
</Constructor>
{/* Add some custom method */}
<Method name="someMethod">
<Argument name="displayName" />
<Argument name="email" />
<Body>
return email === displayName;
</Body>
</Method>
</Class>
Must have to be implemented:
<Module>
(for CommonJS), <Import>
(or <Imports>
), <Class>
, <Constructor>
, <Method>
, <Argument>
(as parameter in method/constructor), <Setter>
(or <SetAccessor>
), <Getter>
(or <GetAccessor>
), <Function>
, <Body>
, <Property>
. Getter and Setter could be include in <Accessors>
component. String inside Method component could be treated as Body component.
Nice to have:
<Variable>
(as standalone variable), then <Object>
, <Array>
etc..., <Lambda>
For Typescript also:
<Interface>
, <Type>
, <Decorator>
, <Enum>
, <Declare>
.
<Namespace name="temp">
<Class name={commonModel.uid()}>
{
Object.entries(commonModel.properties()).map((propertyName, property) => {
return (
<Property
property={property}
private
name={propertyName}
>
<SetAccessor public />
<GetAccessor public />
</Property>
)
})
}
{/* Custom constructor beside default constructor */}
<Constructor>
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
this.displayName = displayName;
this.email = email;
</Body>
</Constructor>
{/* Add some custom method */}
<Method public name="someMethod" returnType="bool">
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
return email == displayName;
</Body>
</Method>
</Class>
</Namespace>
Must have to be implemented:
<Namespace>
, <Import>
(or <Imports>
), <Class>
, <Interface>
(like <Class>
with virtual methods), <Enum>
, <Struct>
, <Constructor>
, <Destructor>
<Method>
, <Argument>
(as parameter in method/constructor), <Setter>
(or <SetAccessor>
), <Getter>
(or <GetAccessor>
), <Function>
, <Body>
, <Property>
. Getter and Setter could be include in <Accessors>
component. String inside Method component could be treated as Body component.
Nice to have:
<Using>
, <Union>
, <Lambda>
.
<>
<Data name={commonModel.uid()}>
{
Object.entries(commonModel.properties()).map((propertyName, property) => {
return (
<Property
property={property}
name={propertyName}
/>
)
})
}
</Data>
<Instance class="ToJSON" data={commonModel.uid()}>
... implementation of toJSON function
</Instance>
<Instance class="FromJSON" data={commonModel.uid()}>
... implementation of parseJSON function
</Instance>
</>
Must have to be implemented:
<Module>
<Import>
(or <Imports>
), <Data>
, <Class>
, <Instance>
, <Function>
, <Type>
.
<Struct name={commonModel.uid()}>
{
Object.entries(commonModel.properties()).map((propertyName, property) => {
return (
<>
<Property
property={property}
private
name={propertyName}
>
<Annotation name="json" value={propertyName} />
</Property>
<SetAccessor public property={property} name={propertyName} />
<GetAccessor public property={property} name={propertyName} />
</>
)
})
}
<Constructor>
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
return {commonModel.uid()}{`{displayName, email}`}
</Body>
</Constructor>
{/* Add some custom method */}
<Method name="someMethod" returnType="bool">
<Argument name="displayName" type="string" />
<Argument name="email" type="string" />
<Body>
return displayName
</Body>
</Method>
</Class>
Constructor
is the same as:
<Method name={`New${commonModel.uid()}`} returnType={commonModel.uid()}>
<Argument type="string" name="displayName" />
<Argument type="string" name="email" />
<Body>
return {commonModel.uid()}{`{displayName, email}`}
</Body>
</Method>
Must have to be implemented:
<Package>
<Import>
(or <Imports>
), <Struct>
, <Constructor>
(as New*
Method), <Method>
, <Argument>
(as parameter in method/constructor), <Setter>
(or <SetAccessor>
), <Getter>
(or <GetAccessor>
), <Function>
, <Body>
, <Enum>
, <Interface>
, <Type>
, <Property>
(for Struct), <Tag>
(or <Annotation>
for Struct's Property). Getter and Setter could be include in <Accessors>
component. String inside Method component could be treated as Body component.
Nice to have:
<Variable>
(as standalone variable), <Const>
(as standalone const) -> https://www.callicoder.com/golang-typed-untyped-constants/
If we go with React engine as a base solution for model generation, then we should also introduce context for React components. It should works similar to React-DOM context. Let's check the example:
<NamespaceContext>
<Namespace>
<ClassContext>
<Class>
<PropertyContext>
<Property />
</PropertyContext>
<MethodContext>
<Method />
</MethodContext>
</Class>
</ClassContext>
</Namespace>
</NamespaceContext>
Then inside Property
and Method
components we can use contexts: NamespaceContext
, ClassContext
, PropertyContext
(only Property can use it) and MethodContext
(only Method can use it). In Class component we can use contexts: NamespaceContext
, ClassContext
. By this we lookup for contexts in parent components (not in children - it is not logical).
Using context in component:
import { useContext } from "@asyncapi/generator-react-sdk";
function Property({ ...props }) {
// we can retrieve some data from ClassContext
const { className } = useContext(ClassContext);
// and also from NamespaceContext
const { namespaceName } = useContext(NamespaceContext);
}
Context can store some data (because context can be written and used as normal JS class) in rendering time and then developer can change output based on stored data.
/progress 75 Prepare implementation examples for each language using React
@magicmatatjahu what is left for this issue?
@jonaslagoni Actually nothing, but we can close this issue before start date of second cycle, what do you think?
@magicmatatjahu if its done just close it now, the new issue has all the references to the issues 😄
/progress 100 Finish investigation
Part of https://github.com/asyncapi/shape-up-process/issues/21 issue:
Check correlations between languages - similarities and differences in how a given language handles similar tasks and their overall syntax of what is allowed and what is not.
Things to check:
Try to create structure in language (by class/function/structure) from this json schema:
Try to create from above schema data model (using React or pure json) something like:
and check differences between languages.
@magicmatatjahu languages:
@jonaslagoni languages: