-
Notifications
You must be signed in to change notification settings - Fork 0
Why Sq
Maybe you ask what is the point of Sq, or why did i created it. What is the purpose, how to use it, what does Sq provide, and so on. So here i try to give a small explanation on why i created it.
I am now programing since a very long time. I started back in the 90s with QBasic. After 2 days i started to learn C, later on C++, Visual Basic, Vidual C++. In the early 2000s i came into contact with Perl because of system administration and mostly i learned and used Perl. But still i learned JavaScript as i did Web-Development. I also learned C# because i learned Unity Game Development, some F# and besides that other stuff like some Scheme, Haskell and so on.
After having experience with procedural languages, OO languages and functional languages from dynamic and static-typed i learned a lot, and also learned what works, and what i consider crap. After a lot of learning i came to the conclusion that mostly the "OO" and object-orientet trend was probably the most harmful to programming. In nearly 30 years of learning programming, the most stuff i regret is the whole OO-crap, and also believing all it's myths about being better, less error-prone because of inheritance or reusable code. I learned that OO is the worst of all of them.
My two most favorable programming languages are actually Perl and F#.
I like F# because you can see how a minimal syntax can be extremely powerful without adding a new syntax construct every month. Sadly Perl, as many other languages, also does the same. Adding syntax constructs for new features instead of just trying to solve it with functions. It can be very interesting to learn a LISP-like language and see how it can be more powerful by having the least amounf of syntax. An ML-like language like F# offers more syntax compared to LISP. But it is still interesting to see a language for 20 years, doing improvment and adding features without ever adding new syntax.
Why I like F#, especially it's clean syntax, i don't like the ecosystem of F#. Here I mean the way how people write librarires for it with it's API. Instead of making things easy/usable/simple most go down the Haskell route it seems and trying to make F# more like Haskell. The amount of "special-operators" some F# libraries implement are insane, and once you didn't use a librarie for a week, you maybe forget all the operators and what they did.
Also the APIs are full of exceptions. Typically functional programming is about avoiding them. While F# provide an Option / Result type there are rarely used. Option is not used by default and you have to call special try functions to get the function that return Option. Mostly you just get Exceptions by default. Result as an error mechansim was implemented by default, but not used by the standard libraries at all.
Also a lot of .Net libraries are written to be used from C# and are very awkward to use from F#. And additionaly, like C# programmers. People have no clue about Hashes. They just use List everywhere.
Perl is still my favorite language. What makes it great is that i just can open a file, and start coding. There are a lot of modules out there with a simple and clean API. For example trying to read a CSV file in Perl is just loading a module. Call a single function and get an array of hashes. In F# on the other hand you must first write classes and map them. Or you rely on FSharp.Data that comes with some magic on it, doing stuff for you, but you don't have any clue what todo when it doesn't do what you want.
The dynamic-typing nature makes a lot of stuff easier in Perl. Especially when it comes to reading any kind of data from different formats like JSON, XML or just parsing text because of it built-in Regex implementation.
Also Perl starts fast. Doesn't mean the exsecution itself is the fastest but even very complex code with multiple thousand of lines can start "instantly", while F# needs 3 seconds to compile/start a F# Script file that just prints "Hello, World".
So there are still reasons why I use Perl over F#. For a lot of stuff it is just better. But, for me there was something missing in Perl.
So in the past i have written a lot of small helper scripts in Perl, i don't do coding anymore for a living and don't do bigger projects like Web/Gaming anymore. So here is something what i noticed. Often i start a project very easy, some direct implement, more procedural code, and a mix of functional code in it.
Usually the result i get was.
I end up being fast. This means i have something working very fast. I also did some re-writes of some kind of scripts i thought to make it "better", so i converted scripts and used "Moose", make them proper objects, added type-checking with stuff like Type::Standard and so on. Often the result i got was.
- Code becomes harder to read/understand
- twice the source-code (or more)
- Slower in execution
So i got more and more annoyed. Often i found that just coding in a procedural Perl style like i did at he early 2000 was the best and fastest way of coding. Usually results into better code, faster code, and because of that also code with less bugs. The only thing I was very annoyed was that i was missing my "Utility-Belt" that i know from F#.
What i mean with this is that F# for example ships with over 100 functions that somehow process an Array, do some modification on it, and so on. In Perl you somehow get those with List::Util and List::Moreutils to know what i mean with that. If something is not in there you must rewrite it yourself.
But the biggest disadvntage is that you only get those functions for an Array. That means all data must be completely read into memory. No lazy sequence is provided. You cannot use map, grep and all other functions without reading everything into memory at once. Sometimes that is possible, sometimes not.
Also sometimes it is not about memory, it is just about providing immediat output for complex calculations that takes time. Often this then needs you must write code again with simple for-loops and don't use all those nice functions. Sq solves that problem by providing Array and Seq. Both modules provide all those helper functions you are used to, but also are written with a API so they can work on Array and a lazy sequence Seq seaminglessly.
So you just need to learn one API, and get two data-structures. While implementing those data-structures I also made Option and Result data-types the default. For example what should min return on an empty Array? I want to avoid undef as much as possible because of the problem it creates. So i return Option by default.
And why do we just provide helper functions for Array? I also provide nearly ~100 functions for Hash too.
But it is not just those helper functions that makes programming a lot faster. Also i started to try to fix other stuff as i was used from F#. In F# i was used that you basically can compare any data-structure by default, without ever rewriting your own equal implementation. So now Sq also provides a equal function that does the same.
Sometimes you want to make a copy, because we still have mutable data. So it also provides a copy that can recursively copy any data-structure.
One of the most useful way how i learned to program, fix bug and so on is still through dumping data. I have used Debuggers in the past and never seen them very useful. Often print Debugging beats them all. You just run a program and look into your data to identify a spot very fast. Instead of going through your code step by step and examing data.
And when you have data anyway, consider that Testing is basically just comparing data. Usually you have something in a starting state. Then you do some operations. Then you test if the values are in the state you expect. Otherwise it is an error. So testing is basically just comparing data. Isn't it best to also have a dump tool that just can dump data that you just can put into an Test?
Well Sq provides exactly that. And the dumping tool dumps into a human readable format. And in a way how data can be created. As long it is possible. For example when you dump($x) from my $x = Some(1) you also get Some(1) dumped. Not how it is internally represented through blessed perl objects.
But also this means Testing must be updated. For example when i have two lazy sequences i can compare them with equal and it does so in a lazy way. But testing tools like Test2 instead try to compare different blessed objects. So Sq also ships with it's own Test System.
Also consider that i stripped down most of the stuff to it's most simple form, not to provide any kind of feature that is barely used. The result is a much more simple, easy to use system that usually is a lot faster. When i for example replaced Test2 with my own Test system, running the Test-Suite went down from 5 seconds to around 1 seconds. This was when i had around ~2000 tests.
Now i am at the ~3000 tests or more and barely hit 3 seconds.
Since them i also implemented a Type-System a Parser and a lot of other stuff all on top of it, and part of the Test-Suite.
I am actually proud of how the type system works, because i hated the way as many other worked. Perl is a dynamically typed langauge, so it means any type is basically code that must run at runtime and check it's values. The problem is that this costs much performance. Consider now that this type-system is usually only useful in the case when your code is wrong.
For example let's assume you have a function that must check if an argument is an integer. Most type-systems in Perl let's you add those checks, but once you add those, those checks are always active, eating some performance and slowing down your program. But most of the time once your code correctly passes an integer and you have written correct code to ensure that, you could deactive that check. But most type-systems are not written that way.
I wanted a system that you can add type-checking at will, like "memoize" does adds caching to any function at will. And i exactly implemented that in Sq. With just use Sq -sig => 1 you can add type-checking to every Sq function. Once your code is correct you can use use Sq and get a performance benefit. You encounter some kind of bug? Just add the signature again, fix your code and disable the type checks again.
You sure can use the type-checking and the signatures yourself. Also a parser was written to make Parsing easier, or a data generator for generating random data. Not everything is fully implemented yet, but i myself use Sq for everything i write in Perl now by default, and my coding just has become faster and less painful.