Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Bloody
Mar 3, 2013

Malcolm XML posted:

is that supposed to yield "22" or 4 b/c the only way to consistently do it is make u state it every time so either "2" ++ (show 2) or (read "2") + 2

the most correct answer is 52

Adbot
ADBOT LOVES YOU

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Bloody posted:

the most correct answer is 52

'2' + 2 should yield 52; "2" + 2 should yield a garbage string :v:

Zombywuf
Mar 29, 2008

code:
~$ perl -e 'print "2" + 2, " ", "2" . 2;'
4 22
Perl supremacy.

gonadic io
Feb 16, 2011

>>=

Otto Skorzeny posted:

'2' + 2 should yield 52; "2" + 2 should yield a garbage string :v:

oh yeah now i've just remembered that python has no characters just 1-length strings and am angry all over again

and i bet it's the most double-down topic ever (other than tail call optimisation) so will never ever be added for egotistical reasons

Tiny Bug Child
Sep 11, 2004

Avoid Symmetry, Allow Complexity, Introduce Terror

Malcolm XML posted:

is that supposed to yield "22" or 4 b/c the only way to consistently do it is make u state it every time so either "2" ++ (show 2) or (read "2") + 2

this is an excellent point and it is the reason why all languages should have separate operators for concatenation and addition. in my opinion, the correct answer is 4, but "22" would also be acceptable, as long as the language's behavior is consistent and documented. when you have separate operators you don't need to worry about that ambiguity

Bloody posted:

the most correct answer is 52

this on the other hand is balls out retarded. i'm guessing this answer is based on ascii character values, which are even more of an implementation detail than what type a variable is.

Bloody
Mar 3, 2013

Otto Skorzeny posted:

'2' + 2 should yield 52; "2" + 2 should yield a garbage string :v:

but if the dream is to live without types then "2" is 0x32 and 0x32 + 0x02 = 0x34

Bloody
Mar 3, 2013

or, even more comedy alternative, "2" is probably actually 0x3200 so 0x3200 + 0x02 = 0x3202

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

Tiny Bug Child posted:

this is an excellent point and it is the reason why all languages should have separate operators for concatenation and addition. in my opinion, the correct answer is 4, but "22" would also be acceptable, as long as the language's behavior is consistent and documented. when you have separate operators you don't need to worry about that ambiguity


this on the other hand is balls out retarded. i'm guessing this answer is based on ascii character values, which are even more of an implementation detail than what type a variable is.

i stole this from the last time this poo poo came up

but anyway tbc doesn't do anythign but porn websites so who even cares if he drops the database or some poo poo every other day

gonadic io
Feb 16, 2011

>>=
also clearly the type of "2" + 2 should be Either String Int (String, Int)

e: whoops

gonadic io fucked around with this message at 19:58 on Apr 30, 2014

Bloody
Mar 3, 2013

"2" + 2 should be a <string, int> tuple containing "2" and 2

gonadic io
Feb 16, 2011

>>=
"2" + 2 should be the superposition of 4 and "22"

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
incidentally the example i gave last page of task handles and queue handles was a real bug caused by an rtos emulating php by exposing every handle type as a pointer to void externally (lol @ doing atrocities in the name of information hiding)

Tiny Bug Child
Sep 11, 2004

Avoid Symmetry, Allow Complexity, Introduce Terror

Malcolm XML posted:

but anyway tbc doesn't do anythign but porn websites so who even cares if he drops the database or some poo poo every other day

this is what someone eventually says every time this discussion happens and we reach the inevitable conclusion that static typing is unnecessary when you aren't working on something that can kill people if it fucks up once. i have always advocated taking the proper care when appropriate, but it turns out the extreme overabundance of caution static typing entails is rarely appropriate, either for my porn sites or for whatever glorified database skins 95% of you out there in yosland happen to be working on.

MrMoo
Sep 14, 2000

AlsoD posted:

Java code:
String[] arrStrings = ...
List<String> strings = Arrays.asList(arrStrings); // works fine

int[] arrInts = ...
List<int>     ints = Arrays.asList(arrInts); // doesn't compile, can't have primitives in generics
List<Integer> ints = Arrays.asList(arrInts); // doesn't compile, can't autobox an array
List<int[]>   ints = Arrays.asList(arrInts); // compiles, is a list of one element which is the array
now i have to actually write a loop like it's 1995, jesus christ

Would something retarded like this compile?

Java code:
List<Integer> ints = Arrays.asList (Arrays.copyOf (arrInts, arrInts.length, Integer[].class));
In Guava its easy, Ints.asList (arrInts)

MeruFM
Jul 27, 2010
porn sites are also serious business

people notice right away when swaths of content is missing

Sapozhnik
Jan 2, 2005

Nap Ghost

Tiny Bug Child posted:

i will ask again: what loving mistakes are you people making that are caught by static typing? cause no, apparently i don't ever make those mistakes. i make plenty of mistakes but i can't remember the last one that would have been prevented if php had static typing.

typos

MononcQc
May 29, 2007


Most of these can be found by a compiler without doing any actual type checking. You can have compiled languages that still keep type tags and have these types evaluated at run time and be dynamic.

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

MononcQc posted:

Most of these can be found by a compiler without doing any actual type checking. You can have compiled languages that still keep type tags and have these types evaluated at run time and be dynamic.

yeah but why wait til runtime when u can do it compile time?

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

Tiny Bug Child posted:

this is what someone eventually says every time this discussion happens and we reach the inevitable conclusion that static typing is unnecessary when you aren't working on something that can kill people if it fucks up once. i have always advocated taking the proper care when appropriate, but it turns out the extreme overabundance of caution static typing entails is rarely appropriate, either for my porn sites or for whatever glorified database skins 95% of you out there in yosland happen to be working on.

p much but i find static typing (good static typing like haskell/ocaml etc) makes writing programs a bunch easier since there are far fewer syntactically correct programs that are semantically wrong that will pass the typechecker.

gently caress java types tho that poo poo sucks

and u need some level of dynamism to deal with the real world; type providers are actually a nice solution to a lot of problems.

MononcQc
May 29, 2007

Malcolm XML posted:

yeah but why wait til runtime when u can do it compile time?

Because a type checker on a language will impose semantics on it that you may or may not want in the end.

To make a very brief argument, static type checkers like Hindley-Milner start with a bottom type and gradually add what is acceptable as information is gathered from the source. When information is lacking to prove the absence of errors (or the type checker is too dumb to find/infer it), certain operations that would otherwise be valid are denied due to limitations of the checker. Additionally, when information is found, you can't have functions further down the call line only handle a subset of the cases, you need to handle them all, even if in practice, you will never get an error if you were to run the code.

One example for this are multiple input types yielding different output paths. For example, writing a function that has more or less the equivalent of a functional cast/swap -- f(integer) -> float; f(float) -> integer; -- isn't representable in a H-M type system (iirc) because the closest signature you can get is f(integer | float) -> integer | float;, which will represent a loss of information and deny multiple operations that could have been doable had the type checker dropped the 'float' requirement on the output following a 'float' input.

There are many different type systems and checkers that impose different semantics, some that are stricter than others and depend on the context. The one you have in a given language may not be adequate to express all programs you'd wish to express.

MononcQc fucked around with this message at 21:08 on Apr 30, 2014

Tiny Bug Child
Sep 11, 2004

Avoid Symmetry, Allow Complexity, Introduce Terror

MononcQc posted:

Most of these can be found by a compiler without doing any actual type checking. You can have compiled languages that still keep type tags and have these types evaluated at run time and be dynamic.

heck you don't need a compiler. php will spit out a notice on using an undefined variable (but i always disable notices cause making sure every single variable is defined before you use it is some burdensome poo poo, especially when it's just a boolean flag you expect to evaluate to falsish until something important happens)

FamDav
Mar 29, 2008

MononcQc posted:

Because a type checker on a language will impose semantics on it that you may or may not want in the end.

To make a very brief argument, static type checkers like Hindley-Milner start with a bottom type and gradually add what is acceptable as information is gathered from the source. When information is lacking to prove the absence of errors (or the type checker is too dumb to find/infer it), certain operations that would otherwise be valid are denied due to limitations of the checker. Additionally, when information is found, you can't have functions further down the call line only handle a subset of the cases, you need to handle them all, even if in practice, you will never get an error if you were to run the code.

One example for this are multiple input types yielding different output paths. For example, writing a function that has more or less the equivalent of a functional cast/swap -- f(integer) -> float; f(float) -> integer; -- isn't representable in a H-M type system (iirc) because the closest signature you can get is f(integer | float) -> integer | float;, which will represent a loss of information and deny multiple operations that could have been doable had the type checker dropped the 'float' requirement on the output following a 'float' input.

There are many different type systems and checkers that impose different semantics, some that are stricter than others and depend on the context. The one you have in a given language may not be adequate to express all programs you'd wish to express.

at first i thought you were talking about a function that takes an integer or a float and returns a float but then i read closer and i have no idea why you would possibly want a single function that flips the type.

MononcQc
May 29, 2007

FamDav posted:

at first i thought you were talking about a function that takes an integer or a float and returns a float but then i read closer and i have no idea why you would possibly want a single function that flips the type.

It's an example case of such a function.

Imagine you're the owner of a type zoo, and you can only feed type lions with meat puree, and feed type pandas with bamboo puree. However, type monkeys want hard bananas and cannot be fed banana puree.

You could write a blender function that returns blend(meat, carnivore) -> meat_puree; blend(bamboo, panda) -> bamboo_puree; but refuses blend(banana, monkey) -> banana_puree. Everything else gets denied.

However, the Hindley-Milner zoo doesn't have the desire to build such a blender because it can't track its types too well when it comes to branching depending on inputs. This will in turn block a shitload of operations that would be safe, but H-M can't track properly and will declare invalid. You will either need to define whether every type of food can be blended (via supertypes possibly), or create a blender per animal in your type zoo, more or less. It's not because the idea is bad, it's because the type system isn't amenable to representing that idea.

Specific type systems could be able to do so without a problem, though, because they may more easily track the idea that different arguments may yield different image types:

memory(used) -> bytes
memory(allocated) -> bytes
memory(usage) -> float(0..1)

Oh no, you cannot do this, you have to implement functions differently because the type system cannot track this kind of returns easily! Except that some type systems can and will track this poo poo. Just not the H-M you have in language X.

tl;dr: the type system you choose imposes semantics in what you want to write and maybe you disagree with these. It's possible to have an infinite amount of "but in more modern type systems!" arguments that aren't actually about modernism but about what you allow as operations and can detect as safe.

MononcQc fucked around with this message at 21:33 on Apr 30, 2014

Max Facetime
Apr 18, 2009

MrMoo posted:

Would something retarded like this compile?

Java code:
List<Integer> ints = Arrays.asList (Arrays.copyOf (arrInts, arrInts.length, Integer[].class));
In Guava its easy, Ints.asList (arrInts)



List<Integer> collect = IntStream.of(ints).boxed().collect(Collectors.toList());

FamDav
Mar 29, 2008

MononcQc posted:

It's an example case of such a function.

Imagine you're the owner of a type zoo, and you can only feed type lions with meat puree, and feed type pandas with bamboo puree. However, type monkeys want hard bananas and cannot be fed banana puree.

You could write a blender function that returns blend(meat, carnivore) -> meat_puree; blend(bamboo, panda) -> bamboo_puree; but refuses blend(banana, _) -> banana_puree.

However, the Hindley-Milner zoo doesn't have the desire to build such a blender because it can't track its types too well. You will either need to define whether every type of food can be blended, or create a blender per animal in your type zoo, more or less. It's not because the idea is bad, it's because the type system isn't amenable to representing that idea.

Specific type systems could be able to do so without a problem, though, because they may more easily track the idea that different arguments may yield different image types:

memory(used) -> bytes
memory(allocated) -> bytes
memory(usage) -> float(0..1)

Oh no, you cannot do this, you have to implement functions differently because the type system cannot track this kind of returns easily! Ergo, the type system imposes semantics in what you want to write.

So your first example is asking for blend :: (Food f, Animal a) -> f -> a -> Maybe (Blended f) or something like that.

As for the second example, why do you want them to have the same name?

Like I get your argument from a "technically this is a true statement" but I don't understand from your arguments why this is affecting you negatively, besides the fact that you're probably writing bad code.

Bloody
Mar 3, 2013

Max Facetime posted:

List<Integer> collect = IntStream.of(ints).boxed().collect(Collectors.toList());

java always seems so close and yet so far

MononcQc
May 29, 2007

FamDav posted:

So your first example is asking for blend :: (Food f, Animal a) -> f -> a -> Maybe (Blended f) or something like that.

As for the second example, why do you want them to have the same name?

Like I get your argument from a "technically this is a true statement" but I don't understand from your arguments why this is affecting you negatively, besides the fact that you're probably writing bad code.

For the first example, that's a way to do it. Except now I've got to handle Option types and work with them, whereas in the system I would have liked, this may just not have been necessary because I know (and could express it if the type system allowed it) that you can either deny the thing at compile time, or give it the go-ahead without altering the types at all. At this point, I have to work my program to match what the type checker wants, without any effect on program correctness, because it didn't allow otherwise.

For the second example: I may just prefer having that API. Like maybe you do whitelisting of allowed function names to call in an public-facing API that comes from serialization in a URL (or whatever), and rather than maintaining an ever growing whitelist, I want to extend the capability of the 'api/memory' functionality I expose to the world. Now instead of doing just that, I need to write some kind of adapter in between what I expose and what the type checker wants to see because it imposes constraints that are entirely due to its design, and have no impact on the type-safety of the program in practice.

It's a more subtle form of needing to tell the type-checker about what types my program uses. Except instead of being able to point it out in type signatures (which in this case, would allow independent non-overlapping function clauses to be expressed), I have to point it out through hoops in the code I write or through special code forms and/or option types that will be explicit enough for the type checker to go "oh I see what you mean, sorry for not getting it before".

Nomnom Cookie
Aug 30, 2009



Bloody posted:

java always seems so close and yet so far

there's a platonic ideal of single-dispatch statically-typed OO language and java is as close as we'll ever get

no not ocaml. java.

Nomnom Cookie
Aug 30, 2009



MononcQc posted:

For the first example, that's a way to do it. Except now I've got to handle Option types and work with them, whereas in the system I would have liked, this may just not have been necessary because I know (and could express it if the type system allowed it) that you can either deny the thing at compile time, or give it the go-ahead without altering the types at all. At this point, I have to work my program to match what the type checker wants, without any effect on program correctness, because it didn't allow otherwise.

For the second example: I may just prefer having that API. Like maybe you do whitelisting of allowed function names to call in an public-facing API that comes from serialization in a URL (or whatever), and rather than maintaining an ever growing whitelist, I want to extend the capability of the 'api/memory' functionality I expose to the world. Now instead of doing just that, I need to write some kind of adapter in between what I expose and what the type checker wants to see because it imposes constraints that are entirely due to its design, and have no impact on the type-safety of the program in practice.

It's a more subtle form of needing to tell the type-checker about what types my program uses. Except instead of being able to point it out in type signatures (which in this case, would allow independent non-overlapping function clauses to be expressed), I have to point it out through hoops in the code I write or through special code forms and/or option types that will be explicit enough for the type checker to go "oh I see what you mean, sorry for not getting it before".

i'm starting to suspect this is all some erlang crypto-boosterism

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

MononcQc posted:

Because a type checker on a language will impose semantics on it that you may or may not want in the end.

To make a very brief argument, static type checkers like Hindley-Milner start with a bottom type and gradually add what is acceptable as information is gathered from the source. When information is lacking to prove the absence of errors (or the type checker is too dumb to find/infer it), certain operations that would otherwise be valid are denied due to limitations of the checker. Additionally, when information is found, you can't have functions further down the call line only handle a subset of the cases, you need to handle them all, even if in practice, you will never get an error if you were to run the code.

One example for this are multiple input types yielding different output paths. For example, writing a function that has more or less the equivalent of a functional cast/swap -- f(integer) -> float; f(float) -> integer; -- isn't representable in a H-M type system (iirc) because the closest signature you can get is f(integer | float) -> integer | float;, which will represent a loss of information and deny multiple operations that could have been doable had the type checker dropped the 'float' requirement on the output following a 'float' input.

There are many different type systems and checkers that impose different semantics, some that are stricter than others and depend on the context. The one you have in a given language may not be adequate to express all programs you'd wish to express.

HM is not the end-all be-all of type systems.

U could have the function be of type f(arg : integer|float) -> TypeSwap arg in idris where TypeSwap is a function that maps int to float and back, or have closed type families in haskell.

u lose type inference tho

Socracheese
Oct 20, 2008

Kevin Mitnick P.E. posted:

there's a platonic ideal of single-dispatch statically-typed OO language and java is as close as we'll ever get

no not ocaml. java.

when i learned about java and all the things it does right that C++ utterly fucks up i was like :unsmith:

but every time i code java for longer than 10 minutes i want to die

i end up looking at really bad oracle documentation and i imagine larry ellison laughing at me from the cockpit of a fighter jet

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

Malcolm XML posted:

HM is not the end-all be-all of type systems.

U could have the function be of type f(arg : integer|float) -> TypeSwap arg in idris where TypeSwap is a function that maps int to float and back, or have closed type families in haskell.

u lose type inference tho

actually typeclasses might work with associated types as well

multiple dispatch is handled by MPTCs

MononcQc
May 29, 2007

Malcolm XML posted:

HM is not the end-all be-all of type systems.

U could have the function be of type f(arg : integer|float) -> TypeSwap arg in idris where TypeSwap is a function that maps int to float and back, or have closed type families in haskell.

u lose type inference tho

Right, that was part of the point. Specific type systems aren't always appropriate to properly express all ideas, even if they're modern and advanced. I've always been a fan of optional type systems that let you go dynamic when you need to (even the Haskell extension was pretty sweet for this).

Dynamic types aren't always a bad idea when the alternative available to you is an inadequate type system -- you can compensate through other means, like tests, which even if tedious, in the end do not usually constrain the way you write code the way an inadequate type system may do it.

This is always dependent on the task at hand, and there are plenty of cases where a type system is adequate, still.

MononcQc
May 29, 2007

Kevin Mitnick P.E. posted:

i'm starting to suspect this is all some erlang crypto-boosterism

No. My arguments are influenced by Erlang syntax and semantics because that's what I use day-to-day and it's a language whose semantics couldn't be appropriately represented by H-M (at least, Simon Marlow and Phil Wadler failed to do it without changing the language semantics), so it's easy to go dig there for examples.

I avoided big ones like having unrestricted types in a mailbox, even types that may come from remote nodes running a future version of the program.

Incidentally, Erlang has an optional type system based on Success Typing, which rather than constrain semantics to guarantee error-free type usage, will allow some failures but will guarantee it never gives a false-positive.

I'm also a fan of what languages like Modula-3 did. In Modula-3, it was possible to define modules and interfaces as safe or unsafe. Safe modules could only call other safe modules while benefiting fully from the compiler's powers, and unsafe modules could call anything whether safe or not. This would let you define a safe core and safe set of libraries, but use them freely whenever you felt like and for experimenting and prototyping.

E: Modula-3 didn't necessarily allow super great flexibility in its unsafe modules, but the concept is fairly neat

MononcQc fucked around with this message at 23:18 on Apr 30, 2014

seiken
Feb 7, 2005

hah ha ha
you can do the type-swap in C++ with template specialisation so I'm a little surprised if it really isn't possible in H-M the God-King of functional type systems actually

tef
May 30, 2004

-> some l-system crap ->

Tiny Bug Child posted:

oops i accidentally added the customer's age and name together


:golfclap:

gonadic io
Feb 16, 2011

>>=

seiken posted:

you can do the type-swap in C++ with template specialisation so I'm a little surprised if it really isn't possible in H-M the God-King of functional type systems actually

it was buried at the bottom of Malcolm XML's posts but you absolutely can do this using closed type families.

tef
May 30, 2004

-> some l-system crap ->

Mr Dog posted:

i have enough trouble finding/convincing gophers to help me write poo poo in java

if you're wanting people to work in a project where you make all the decisions, pay them

tef
May 30, 2004

-> some l-system crap ->

MononcQc posted:

While static typing helps, if you think the biggest challenge in scaling a software project is in rooting out type errors, you have been lucky to work with competent teams and managers, haven't worked in larger teams, or are just churning out hobby projects.

I can't believe static types would be more important there than health of team dynamics, having direction, quality of communication and channels, and so on, which will often have the power to kill a project before it even gets started or announce its death before any technical issue will.

if you lose a lot of money when your software fails, then rooting out type errors can be a big challenge. the technical issue becomes a money issue.

choosing to verify your software ahead of time, be it via tests, test generation and fuzzing, type checks and formal proofs, is good but it always comes at an upfront price, as well as regular instalments. the payoffs can be worth it for some.

however, some people don't lose money when their software fails, they just stop making money, which can be ok for a bit. meanwhile, for some companies (notably startups), crashing and failures might mean they can't burn through vc money as fast, so they might be saving money during service outages).

(ps. static vs dynamic is a false dichotomy, except that almost every language makes you choose between them up front. hooray programming! also, pluggable types.)

Adbot
ADBOT LOVES YOU

Sapozhnik
Jan 2, 2005

Nap Ghost

tef posted:

if you're wanting people to work in a project where you make all the decisions, pay them

if they don't like the decisions i made in my project they can go start their own, i'm not rewriting my poo poo in php.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply