Hi,
Is Assembly Language considered a functional programming language?
https://www.quora.com/Is-Assembly-Language-considered-a-functional-programming-language
What do you think?
Ex.1
#include "stdafx.h"
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
// Lambda functions (seit C++11)
// [ capture ] ( params ) -> ret { body }
/*
capture - spezifiziert, welche Symbole erfasst und für den Funktionskörper
sichtbar gemacht werden.
Eine Liste der Symbole kann wie folgt Übergeben werden:
[a,&b], a wird kopiert und b als Referenz erfasst.
[this] erfasst den this-Zeiger als Kopie.
[&] erfasst alle im Funktionskörper verwendeten Symbole als Referenzen.
[=] erfasst alle im Funktionskörper verwendeten Symbole als Kopien.
[] es wird nichts erfasst.
params - Die Liste der Parameter, wie in benannten Funktionen
ret - Der Rückgabetyp. Falls nicht vorhanden, wird er von den return-Statements der Funktion
abgeleitet (oder, falls jene nichts zurückgibt, void)
*/
std::string s = "Hello, Lambda Expressions in C++11!";
for_each(s.begin(), s.end(),
[](char c) { cout << c; }
);
return 0;
}
Ex.2
class Lambda
{
public:
int compute(int &value){
auto get = [&value]() -> int {
return 11 * value;
};
return get();
}
};
int main(){
Lambda lambda;
int value = 77;
return lambda.compute(value);
}
main: # @main
push rax
mov dword ptr [rsp + 4], 77
mov rdi, rsp
lea rsi, [rsp + 4]
call Lambda::compute(int&)
pop rcx
ret
Lambda::compute(int&): # @Lambda::compute(int&)
push rax
mov qword ptr [rsp], rsi
mov rdi, rsp
call Lambda::compute(int&)::{lambda()#1}::operator()() const
pop rcx
ret
Lambda::compute(int&)::{lambda()#1}::operator()() const: # @Lambda::compute(int&)::{lambda()#1}::operator()() const
mov rax, qword ptr [rdi]
mov eax, dword ptr [rax]
lea ecx, [rax + 4*rax]
lea eax, [rax + 2*rcx]
ret
Probably some have old views of assembly as non macro assembler old dos
Specialised critical section coded in asm
, but with lots of helper macros,translated. H files, coinvoke macros for. COM calls,you can do anything
Hi,
I think it's better to keep separated the two worlds. The assemly language should preserve it's essence.
Erol, :thumbsup:
Having a quick read from the article, it sounds like a load of waffle, effectively playing musical chairs with different notions of computer languages. I well understand conventional classic languages, asm, basic, C, pascal as well as COBOL and FORTRAN for the old fellas but most of the rest end up on the trash heap of history and while there is a place for specialised languages for more dedicated tasks, as the tasks change, so does the specialised language.
Just for example, look at modern graphics, GPU processing tends to be brand specific, some stuff runs on Nvidia, other stuff runs on AMD Radeon and similar but as video hardware changes, so too will the libraries that it uses. I am much of the view, learn a classic language (or 3) and branch from their if you have some reason to use a specialised language.
As a humerous aside, my old dev box has an Nvidia 960 which is about 5 years old while the new boxes I have built have Radeon RX 580s and when I moved a video project from my old box to one of the new ones with identical CPU and memory, the speed difference was in the graphics cards and the old Nvidia card was faster than the Radeon.
Hi LiaoMi!
Look like you are using compiler part of some JWASM family.
Quote from: LiaoMi on March 30, 2021, 07:14:45 PM
main: # @main
push rax
mov dword ptr [rsp + 4], 77
mov rdi, rsp
lea rsi, [rsp + 4]
call Lambda::compute(int&)
pop rcx
ret
Lambda::compute(int&): # @Lambda::compute(int&)
push rax
mov qword ptr [rsp], rsi
mov rdi, rsp
call Lambda::compute(int&)::{lambda()#1}::operator()() const
pop rcx
ret
Lambda::compute(int&)::{lambda()#1}::operator()() const: # @Lambda::compute(int&)::{lambda()#1}::operator()() const
mov rax, qword ptr [rdi]
mov eax, dword ptr [rax]
lea ecx, [rax + 4*rax]
lea eax, [rax + 2*rcx]
ret
How you make that in Assembly? Perhaps you can disassemble that part.
Thanks in advance, HSE
deleted
deleted
:biggrin: asmc32 -pe -gui -ws fprog1.asm
Asmc Macro Assembler Version 2.32.25
fprog1.asm(22) : error A2114: INVOKE argument type mismatch : 2
22 .return lambda.compute(value)
deleted
Thanks :thumbsup:
Quote from: daydreamer on March 30, 2021, 11:05:23 PM
Probably some have old views of assembly as non macro assembler old dos
Specialised critical section coded in asm
, but with lots of helper macros,translated. H files, coinvoke macros for. COM calls,you can do anything
Hi daydreamer,
the question is how it should look in assembly language, since functions pass the results in a chain, and nothing is known about the data type. Examples should show how it might look :tongue:
Quote from: Vortex on March 31, 2021, 12:31:41 AM
Hi,
I think it's better to keep separated the two worlds. The assemly language should preserve it's essence.
Hi Vortex,
I completely agree! Functional programming follows a different logic than low-level programming.
Quote from: hutch-- on March 31, 2021, 12:34:37 AM
Erol, :thumbsup:
Having a quick read from the article, it sounds like a load of waffle, effectively playing musical chairs with different notions of computer languages. I well understand conventional classic languages, asm, basic, C, pascal as well as COBOL and FORTRAN for the old fellas but most of the rest end up on the trash heap of history and while there is a place for specialised languages for more dedicated tasks, as the tasks change, so does the specialised language.
Just for example, look at modern graphics, GPU processing tends to be brand specific, some stuff runs on Nvidia, other stuff runs on AMD Radeon and similar but as video hardware changes, so too will the libraries that it uses. I am much of the view, learn a classic language (or 3) and branch from their if you have some reason to use a specialised language.
As a humerous aside, my old dev box has an Nvidia 960 which is about 5 years old while the new boxes I have built have Radeon RX 580s and when I moved a video project from my old box to one of the new ones with identical CPU and memory, the speed difference was in the graphics cards and the old Nvidia card was faster than the Radeon.
Hi Hutch,
I think this is a programming paradigm, not the language itself or a property of the language.
"In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that map values to other values, rather than a sequence of imperative statements which update the running state of the program." - https://en.wikipedia.org/wiki/Functional_programming
Quote from: HSE on March 31, 2021, 01:06:21 AM
Hi LiaoMi!
Look like you are using compiler part of some JWASM family.
Quote from: LiaoMi on March 30, 2021, 07:14:45 PM
main: # @main
push rax
mov dword ptr [rsp + 4], 77
mov rdi, rsp
lea rsi, [rsp + 4]
call Lambda::compute(int&)
pop rcx
ret
Lambda::compute(int&): # @Lambda::compute(int&)
push rax
mov qword ptr [rsp], rsi
mov rdi, rsp
call Lambda::compute(int&)::{lambda()#1}::operator()() const
pop rcx
ret
Lambda::compute(int&)::{lambda()#1}::operator()() const: # @Lambda::compute(int&)::{lambda()#1}::operator()() const
mov rax, qword ptr [rdi]
mov eax, dword ptr [rax]
lea ecx, [rax + 4*rax]
lea eax, [rax + 2*rcx]
ret
How you make that in Assembly? Perhaps you can disassemble that part.
Thanks in advance, HSE
Hi HSE,
this is a
clang compiler that can be used in a visual studio. You can see here - https://godbolt.org/ (Clang 11)
#include <stdio.h>
class Lambda
{
public:
int compute(int &value){
auto get = [&value]() -> int {
return 11 * value;
};
return get();
}
};
int main(){
Lambda lambda;
int value = 77;
return lambda.compute(value);
}
Quote from: nidud on March 31, 2021, 03:02:41 AM
I added direct assignment of strings to Asmc.
- this was possible using = &@CStr( ... )
include iostream
.code
main proc
.new s:string_t = "Hello, Lambda Expressions in C++11!"
.for ( rbx = rax : byte ptr [rbx] : rbx++ )
.new c:char_t = [rbx] ; need signed byte (https://github.com/nidud/asmc/blob/master/include/iostream#L44)
cout << c
.endf
cout << endl
.return 0
main endp
end main
Quote from: nidud on March 31, 2021, 03:15:32 AM
.class Lambda
.static compute value:abs {
imul eax,value,11
}
.ends
.code
main proc
.new lambda:Lambda
.new value:int_t = 77
.return lambda.compute(value)
main endp
push rbp
mov rbp, rsp
sub rsp, 48
mov dword ptr [rbp-0CH], 77
imul eax, dword ptr [rbp-0CH], 11
leave
ret
Hi nidud,
very cool! :eusa_clap: :thumbsup:
I did a couple of tests and realized that this paradigm can only be used at the meta level, i.e. at a high level of language.
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
// Lambda functions (seit C++11)
// [ capture ] ( params ) -> ret { body }
/*
capture - spezifiziert, welche Symbole erfasst und für den Funktionskörper
sichtbar gemacht werden.
Eine Liste der Symbole kann wie folgt Übergeben werden:
[a,&b], a wird kopiert und b als Referenz erfasst.
[this] erfasst den this-Zeiger als Kopie.
[&] erfasst alle im Funktionskörper verwendeten Symbole als Referenzen.
[=] erfasst alle im Funktionskörper verwendeten Symbole als Kopien.
[] es wird nichts erfasst.
params - Die Liste der Parameter, wie in benannten Funktionen
ret - Der Rückgabetyp. Falls nicht vorhanden, wird er von den return-Statements der Funktion
abgeleitet (oder, falls jene nichts zurückgibt, void)
*/
std::string s = "Hello, Lambda Expressions in C++11!";
for_each(s.begin(), s.end(),
[](char c) { cout << c; }
);
return 0;
}
*.asm https://godbolt.org/
__cxx_global_var_init: # @__cxx_global_var_init
push rax
movabs rdi, offset std::__ioinit
call std::ios_base::Init::Init() [complete object constructor]
movabs rdi, offset std::ios_base::Init::~Init() [complete object destructor]
movabs rsi, offset std::__ioinit
movabs rdx, offset __dso_handle
call __cxa_atexit
pop rax
ret
main: # @main
sub rsp, 120
mov dword ptr [rsp + 116], 0
lea rdi, [rsp + 72]
mov qword ptr [rsp + 16], rdi # 8-byte Spill
call std::allocator<char>::allocator() [complete object constructor]
mov rdx, qword ptr [rsp + 16] # 8-byte Reload
mov esi, offset .L.str
lea rdi, [rsp + 80]
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [complete object constructor]
jmp .LBB1_1
.LBB1_1:
lea rdi, [rsp + 72]
call std::allocator<char>::~allocator() [complete object destructor]
lea rdi, [rsp + 80]
mov qword ptr [rsp + 8], rdi # 8-byte Spill
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::begin()
mov rdi, qword ptr [rsp + 8] # 8-byte Reload
mov qword ptr [rsp + 48], rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::end()
mov rcx, rax
mov qword ptr [rsp + 40], rcx
mov rdi, qword ptr [rsp + 48]
mov rsi, qword ptr [rsp + 40]
call main::$_0 std::for_each<__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, main::$_0>(__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, main::$_0)
jmp .LBB1_2
.LBB1_2:
mov dword ptr [rsp + 116], 0
lea rdi, [rsp + 80]
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
mov eax, dword ptr [rsp + 116]
add rsp, 120
ret
mov rcx, rax
mov eax, edx
mov qword ptr [rsp + 64], rcx
mov dword ptr [rsp + 60], eax
lea rdi, [rsp + 72]
call std::allocator<char>::~allocator() [complete object destructor]
jmp .LBB1_5
mov rcx, rax
mov eax, edx
mov qword ptr [rsp + 64], rcx
mov dword ptr [rsp + 60], eax
lea rdi, [rsp + 80]
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
.LBB1_5:
mov rdi, qword ptr [rsp + 64]
call _Unwind_Resume@PLT
main::$_0::operator()(char) const: # @"main::$_0::operator()(char) const"
sub rsp, 24
mov al, sil
mov qword ptr [rsp + 16], rdi
mov byte ptr [rsp + 15], al
movabs rdi, offset std::cout
movsx esi, byte ptr [rsp + 15]
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char)
add rsp, 24
ret
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
push rax
call __cxx_global_var_init
pop rax
ret
.L.str:
.asciz "Hello, Lambda Expressions in C++11!"
Quote from: LiaoMi on March 31, 2021, 08:34:16 AM
"... rather than a sequence of imperative statements which update the running state of the program"
And that pretty much describes assembly language. Assembly code is a sequence of commands (instructions) changing the contents of memory and registers, and interacting with devices.
This is imperative programming, the conventional form of programming.
The C programmers style of using mostly local variables, maybe is more correct to say paradigm?
Ironic ever since non line numbers programming languages,with argument about it should be better with structured programs and later oop,when it's compiled into opcodes it's returns to kinda line numbering in shape of memory addresses :tongue: :biggrin:
Everything that can be done in a high level language can be done in assembly, too - for obvious reasons. The question is do I want it? This JavaScript Side-by-side comparison of imperative vs. functional programming (https://en.wikipedia.org/wiki/Functional_programming#Side-by-side_comparison_of_imperative_vs._functional_programming) looks thrilling:
const numList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result = 0;
for (let i = 0; i < numList.length; i++) {
if (numList[i] % 2 === 0) {
result += numList[i] * 10;
}
}
const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.filter(n => n % 2 === 0)
.map(a => a * 10)
.reduce((a, b) => a + b);
But I'll jump on this train only if a functionally programmed Visual Studio "Express" loads in much less than 3 minutes :cool:
I have this disposition that for all of the abstractions, underneath them is good old fashioned procedural programming, any decent compiler converts its notation to mnemonics and CPU hardware only understands mnemonics.
You can encapsulate many forms of binary code, libraries, DLLs or use scripting languages that call their own engines but on x86 - 64 they are just DLL calls, either from the system or dedicated DLLs for the particular scripting language.
Long ago a friend from the PB forum coined an expression in response to OOP, HOP (hardware oriented programming) and if you want the best performance for any given hardware platform, you write it in its native format.
Now portability is another matter, if you live in the land of console apps, C has long been the master of portable languages and this allows Unix apps to run on other platforms as binary code but there is little portability in UI applications. An alternative is JAVA and some gadget hardware uses JAVA as native code.
Functional programming doesn't require loops and assignments, but needs recursion. So be careful that the memory does not explode.
Gunther