DEV Community

Dustin King
Dustin King

Posted on

What's a useful programming language feature or concept that a lot of languages don't have?

One thing that comes to mind is Ruby's macro-style methods:

class BankAccount < Account
  attr_accessor :balance
  belongs_to :customer
end
Enter fullscreen mode Exit fullscreen mode

What's something your favorite language has that others don't? Or something from a language you tried out that one time and immediately missed it in other languages?

Latest comments (32)

Collapse
 
erebos-manannan profile image
Erebos Manannán

Having worked mostly with Elm, Python and Go lately, there's a LOT of things I miss when working with other languages.

  1. Good and clear ecosystems - Elm's automatic versioning is ingenious, Python has a pretty solid selection of libraries and with Pipenv it's even a bit better than standard, and Go is getting pretty solid as well. There's also no excessive use of microlibraries that add one basic function that everyone depends on multiple times in their dependency tree.

  2. Joy of development - constantly cursing why the language and it's standard libraries are missing very basic things, debugging being a pain, the runtime environments or compilers not catching super obvious errors (ever done a setTimeout(callback(), 1000) and realized that JS engines don't throw exceptions when setTimeout callback is undefined?), are just not things that happen a lot with these languages

  3. Clear standards - gofmt, PEP-8, and similar just save so much headaches. IDEs are configured by default to have one shortcut to reformat the whole file to the language standard, or even just reformat on save, etc. .. saves so much hassle overall

  4. Good concurrency model - Go's channels and goroutines are such an awesome thing to work with, and it always pisses me off when I have to work with any other style because they take so much more work to make reliable

  5. Clear frontend application model - with Elm you get so much certainty over how things are going to work due to how the language is designed. You avoid whole classes of problems because you just always build your applications in a specific way, and it's the right way for at least most cases.

  6. The flexibility - there's almost never a situation where I think "I wonder if I can do this in Python" and the answer is "no". With the whole language being built with well done duck typing instead of e.g. unpredictable type juggling, it's a breeze to do so many things. Similarly with Go, the interface system allows me to customize things a lot more than I would ever have expected from such a low level language.

These are just the things that come to mind in the first few minutes.

Collapse
 
lefebvre profile image
Paul Lefebvre

I think this is more of an underutilized features rather than an uncommon one, but I really like Extension Methods. They allow you to "attach" a method to a class that you otherwise can't or don't want to modify.

For example, rather than:

Foo(FrameworkClass)

You can write:

 FrameworkClass.Foo

In Xojo you'd do this with the Extends keyword in the global method definition:

Public Sub Foo(Extends FrameworkClass As c)
Collapse
 
tobiassn profile image
Tobias SN

Switches and cases. I love them. But when I tried out Python, I was really surprised that it didn’t have them, especially since the C# syntax looks a lot like it could be Python. For example, the Python equivelant of

switch(word):
    case(Hello):
        otherWord = World;
        break;
    case(World):
        otherWord = Hello;
        break;
    default:
        otherWord = FooBar;
        break;

is currently

if word == Hello:
    other_word = World
elif word == World:
    other_word = Hello
else:
    other_word = FooBar

I know that both PEP 275 and PEP 3103 have been rejected, but I have high hopes that a new one is created and accepted.

Collapse
 
moin18 profile image
Moinuddin Quadri

If you are doing simple task which involves just one statement, instead of using if-elif in Python, you may implement switch statements more elegantly using dictionary.

For example:

def switch(key):
     return {
          'a': 'value_a',
          'b': 'value_b'
    }.get(key, 'value_default')

Sample Run:

>>> switch('a')    # 'a' exists as key
'value_a'
>>> switch('z')    # 'z' doesn't exists as key
'value_default'

Above function will return "value" function corresponding to "key". If "key" not found in dictionary, it will return value as "default_value", just like default in switch statements.

Collapse
 
tobiassn profile image
Tobias SN

That's not really a switch statement, but more of a dictionary abstraction. In a real switch, you can run code based on the value. If I were to modify your snippet, I'd have to get busy with functions and stuff.

Collapse
 
cathodion profile image
Dustin King

Maybe it has something to do with having "one way to do it". I never understood the hate for switch/case statements though. It's a little counter-intuitive how they fall through by default in C/C#/C++, but it's still a common thing to want to map a set of possible values to a set of possible actions.

Or return values! Like in Ruby:

    case serial_code
    when /\AC/
      "Low risk"
    when /\AL/
      "Medium risk"
    when /\AX/
      "High risk"
    else
      "Unknown risk"
    end

There's another thing I like from Ruby and Lisp: you don't have to explicitly return, you can just have the return value be whatever the last expression was.

Collapse
 
tobiassn profile image
Tobias SN

Yeah you’re probably right.

Collapse
 
thebadgateway profile image
Will F

pointers - C
templates - C++
decorator syntax - Python
pipes - bash

Collapse
 
jj profile image
Juan Julián Merelo Guervós

Perl 6 grammars
They go many steps further than simple regexes, organizing and systematizing them. Plus they are classes than can use roles, can be subclassed, or have class variables. Here's an article I wrote about them.

Collapse
 
teekay profile image
TK • Edited

In Clojure, I really like the threading macro.

Imagine we have a string " I will be a url slug ", and we want to transform it into a valid "url". Let's build a slugify function to do this transformation.

(defn slugify
  [string]
  (clojure.string/replace
    (clojure.string/lower-case
      (clojure.string/trim string)) #" " "-"))

(slugify " I will be a url slug   ") ;; "i-will-be-a-url-slug"
Enter fullscreen mode Exit fullscreen mode

Here we have:

  • trim: removes whitespace from both ends of string
  • lower-case: converts string to all lower-case
  • replace: replaces all instance of match with replacement in a given string

Another solution is to use the threading macro. Basically we can compose functions using the -> operator.

(defn slugify
  [string]
  (-> string
      (clojure.string/trim)
      (clojure.string/lower-case)
      (clojure.string/replace #" " "-")))

(slugify " I will be a url slug   ") ;; "i-will-be-a-url-slug"
Enter fullscreen mode Exit fullscreen mode

Beautiful!

PS. another solution is to compose all function using comp function :)
PS2. I wrote a post about Functional Programming with Clojure

Collapse
 
cathodion profile image
Dustin King • Edited

It's nice not having to work backwards:

"Take the string, then do x to it, then do y to it"

instead of

"Take the result doing z to the result of doing y to the result of doing x to the string".

I once wrote something to let you do this in Python:

def incd(x, by=1):
    return x + by

print('7 ==', fv(1).incd().incd(2).incd(by=3))
#=>  7 == 7
Enter fullscreen mode Exit fullscreen mode

Python had the idea that methods are just functions (hence having an explicit self parameter), it just didn't take it far enough.

Collapse
 
jvanbruegge profile image
Jan van Brügge • Edited

Monads. Seriously! They make composing function so easy: For example you parse a number for a string the user types in (which might fail if the string is not a number), then you want to index a list at that position (which could fail because the list might be shorter) and then you want to print the element at that position out or an error if a previous step failed. In Haskell this looks like this (I added the type signatures of the functions used on top):

readMaybe :: String -> Maybe Int
indexMaybe :: [String] -> Int -> Maybe String
fromMaybe :: String -> Maybe String -> String

myList = ["Hello", "World"]

doStuff :: String -> String
doStuff = fromMaybe "Error" . (readMaybe >=> indexMaybe myList)

main = const getLine >=> putStrLn . doStuff $ ()

Here you see the same function (>=>, which has type Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) btw, so it just composes two monadic functions) used for two completely different contexts: First for the Maybe type and then for doing IO. This is the beauty of Monads (and similar type classes). They provide a unified interface over a great range of types. Once you know how to use Monads in general, you can use it on any type that is a Monad. No more consulting the specific API of the library. Everything has the same API!

Collapse
 
rhymes profile image
rhymes

Ahahahaha

Collapse
 
alpercugun profile image
Alper Cugun-Gscheidel • Edited

I miss Swift's strongly typed enums with associated values a lot in other languages (Go, Python etc.).

From the textbook:

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}
Collapse
 
phallstrom profile image
Philip Hallstrom

Thanks for the nightmarish flashbacks! 😂😱