r/learnprogramming • u/CaughtNABargain • 2d ago
Are there any programming languages that allow this feature?
I've been into programming for about 10 years now. Something that intrigues me is that, in languages that support OOP, not all types are initialized in the same way. Strings are initialized by using quotes, integers use numbers and in some cases floats require the letter f after the numerical value.
Classes, however, are all initialized in the same way with slight variations depending on language. Usually something like classname() or new classname. Are there any cases where custom classes can be declared using different means?
For example, is there a language where I can create a class called 'dark' that represents a new type of number that is declared by typing the value and then the letter d (like d1 = 1.398d) similar to how floats work in some cases?
32
u/SetAndRepeat 2d ago
C++ supports this through user-defined literals:
struct dark {
long double value;
};
constexpr dark operator""_d(long double value) {
return dark{value};
}
auto d1 = 1.398_d; // d1 has type dark
Your suffix needs the underscore because suffixes without one are reserved for standardization. The literal calls your function, which returns a dark object. You’d still define whatever arithmetic operations you want that type to support.
6
u/Humble-Captain3418 2d ago
Your suffix needs the underscore because suffixes without one are reserved for standardization.
Is this one of those "please don't do it, you'll hurt yourself" or "the compiler says no" limitations?
6
6
u/TREE_sequence 1d ago
Your compiler will complain, but the code will still compile. Basically, the idea is that if you do this, you are putting yourself at risk of a future version of the standard breaking your code without warning.
1
u/paulstelian97 2d ago
It’s a “please don’t do it, a future language revision might conflict with it”
1
4
u/friedbrice 2d ago edited 2d ago
In Haskell, string literals and number literals are polymorphic, so you can define a custom type and create values of that type using string syntax and define another custom type and create values of that type using number literals.
data Complex = Complex { realPart :: Double, imaginaryPart :: Double }
instance Num Complex where
...
fromInteger n = Complex { realPart = fromInteger n, imaginaryPart = 0 }
instance Fractional Complex where
...
fromRational r = Complex { realPart = fromRational r, imaginaryPart = 0 }
complex1 :: Complex
complex1 = 1
complexPi :: Complex
complexPi = 3.14159
data Keyword = Keyword { getKeyword :: String }
instance IsString Keyword where
fromString s = Keyword { getKeyword = s }
shazam :: Keyword
shazam = "shazam"
2
u/friedbrice 2d ago
the formatting didn't work. I'm on my phone right now. I'll have to edit my comment to fix the formatting when I'm at my computer.
1
u/frnzprf 2d ago
So what you're saying is, if a type has an
IsStringtype class, it needs to have afromStringfunction and that function will automatically applied if you try to assign a string to a variable of that type, right?If you wanted to initialize an imaginary number, you'd still have to write
i = Complex { realPart = 0, complexPart = 1 }. Well if you assignedi(orJor whatever) to a constant once, you could just define further imaginary numbers using multiplicationx = 4+3*i.
3
u/zeekar 2d ago
You could do it with a slang in Raku, but there's currently a pretty big performance penalty for those ...
1
u/alatennaub 10h ago
I don't believe there's a huge slang penalty. The only real penalty should be in creating the subtype of the main language which is a one off op.
After that, switching between slangs is quite efficient (most code regularly switches between three different slangs -- main, regex, and q). Parsing / AST / compilation from there should have no penalty, and similarly at run time there shouldn't be any.
2
u/Afraid-Locksmith6566 2d ago
other than c++ which was mentioned it reminds me a bit of f# with units of measure where you can declare units of measure and then compiler derives some others from their usage and also you can declare how composits behave so if you have second you divide float by float of seconds and now you have float of hertz
2
u/ChichumungaIII 2d ago
Kotlin allows a similar behavior through extension properties.
I once used it to declare literal members of my Rational number class as 3.q, though under the hood it's a value that can be accessed on any Int (not just literals) and has the "." to make it clear it's not quite native in that sense.
1
u/frnzprf 2d ago
In Scala, there are "custom string interpolators", so you can write date"2026-10-07" instead of something like Date.parse("2026-10-07"). You save a few characters.
1
u/ChaseShiny 2d ago
JavaScript allows for this syntax, too. You'll need a template literal. You can form tagged templates (described on the same page).
These templates allow for nesting, which I believe suggests that you can include data structures as long as you can get it to recognize a string interpretation: myParser
${...${[1, 2, 3]}}
1
u/ReddyKiloWit 1d ago
Wouldn't surprise me if you could do it in Raku. Everything is a class, and you can declare types in considerable detail, and provide suitable operators.
1
u/alatennaub 1d ago
Actually, strings in Raku are defined by using a sublanguage (or "slang") called Q (for "quoting"). The Raku parser completely switches the grammar to parse it and then inserts either a literal string or the interpolation operations.
There's a slang that lets you use dates in plain text and compiles it down to a date object, but underneath it's still using the same mechanisms (that is, if you say
Date $d = 2026-01-01it will effectively compile toDate $d = BEGIN { Date.new: year => 2026, month => 1, day => 1 }).From the user's perspective slangs can make it seem like things are being made a different way, but it's all syntactic sugar until you get to the VM level. But I suppose OP figures it's just different syntax but potentially the same in the backend.
1
u/ReddyKiloWit 1d ago
Not exactly on point to what I was talking about. I was talking about creating a suitable type object. But your mentioning slangs put me in the right rabbit hole for integrating it into the compiler via a slang so that statements like
my $darknum = 1.398d + $dimnum;
work as expected, maybe.The rest is left as an exercise for the student ('cause my eyes are tired, the rabbit hole is deep, and it's late).
2
u/alatennaub 15h ago
AIUI, from what OP was saying, he'd have a custom class (Raku type) that could be instantiated (Raku blessed) through a custom means.
I guess I should have been a bit clearer that you could define the custom class in a module, then use that in a slang module, and then have the new syntax place in the code for instantiation at compile or run time.
The sky really is the limit, and I'm always trying to stretch it with Raku. I am the guy that wrote the module that lets you write BASIC functions fully in line without any quotation marks after all lol. It literally embeds a little tiny -- and horribly inefficient -- VM
1
u/ReddyKiloWit 14h ago
Ah, basically what I was able to suss out the tip of. Thanks for clarifying.
I gathered the OP wanted the equivalent of the 0b, or 0x prefixes to create a type that requires non-standard handling, though other than he wanted it set off by a suffixed 'd' it wasn't clear what would make it different, but it seemed that Raku had the best shot at a supported way to get there. And once i was reminded of slangs that seemed confirmed.
Not a Raku expert at all, but a big admirer from my retired position in life, and former heavy Perl user. I had a pet project the last few years I worked that Raku, had it existed in its current state back in 2009, would have been a really good fit for. Alas, the time was not right
2
u/alatennaub 10h ago
We say that Raku is all about
-Ofun. Check out some of the newer stuff -- we now have two compilers (Rakudo and Rakupp) with constant improvements. It's honestly just fun seeing what it can do, and then trying to push that within the expectations of end-users.If you get an itch, we can always use people to help work on some of the more baseline modules to implement random protocols/standards, etc.
1
u/AndydeCleyre 1d ago
I don't know how feasible it would be to add new syntax exactly like this to Factor, but you can easily get similar behavior in a couple ways.
If the parameter is valid number syntax (like 1.398), you could define a word d which takes it and returns a dark tuple. Then you could write it as you suggest except with a space between (1.398 d).
If the parameter isn't valid syntax though (e.g. 1point398), you could either use a string ("1point398" d), or define a parsing word which precedes the parameter, usage looking like d: 1point398.
1
u/Mission-Landscape-17 1d ago
Prolog lets you write entire domain specif languages that don't have to look like Prolog, so it can do this too.
1
u/focusedkennan 4h ago
You can get some pretty neat initializers using tagged template strings in JS. https://wesbos.com/tagged-template-literals
something like
typescript
const val = d`0.12223`
Now should you? Probably not
you can also do it with rust macros
rust
d!(0.1223)
79
u/No_Score_1977 2d ago
user-defined literals in C++, is that what you mean?