2
\$\begingroup\$

What general tips do you have for golfing in Dotty? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Dotty (e.g. "remove comments" is not an answer). Please post one tip per answer.

Also see Tips for golfing in Scala

\$\endgroup\$
  • \$\begingroup\$ I'm willing to award a bounty if any answers this question. (100 if it's trivial or if it expands on one of the tips I've put here already, and 200 if it's really good). Bounty \$\endgroup\$ – user Sep 7 '20 at 20:49
1
\$\begingroup\$

Use parameter untupling

Parameter untupling allows you to write functions accepting a single tuple as input as if they were functions accepting 2 parameters. Basically, you can replace these

list.map{case(a,b)=>a+b}
//and
list.map{case(a,b)=>Seq(a,b)}
//or
list.map(t=>t._1+t._2)
//and
list.map(t=>Seq(t._1,t._2))

with this, which is both shorter and more beautiful.

list.map(_+_)
//and
list.map(Seq(_,_))
\$\endgroup\$
1
\$\begingroup\$

Use @main and toplevel functions

If you need to make a full program, use the @main annotation on a toplevel main method.

@main def main={code}

It's a lot shorter than these 2 approaches:

object M extends App{code}
object M{def main(a:Array[String])={code}}
\$\endgroup\$
1
\$\begingroup\$

Numeric Literals

You can now write a number literal for any user-defined type with a given/implicit instance of the FromDigits trait, such as BigInt and BigDecimal.

In Scala 2, to pass the number 9,999,999,999,999,999 to a function accepting BigInts, you would have to use BigInt("9999999999999999"), but now you can just directly say 9999999999999999 without using the apply method or constructor explicitly.

You can also use underscores, scientific notation, hex, etc., just like any normal number literal, as long as the FromDigits instance for that type supports that notation, of course. Both BigInt and BigDecimal are okay with underscores, but only BigInt allows hex, and only BigDecimal allows scientific notation (with decimals).

\$\endgroup\$
  • 1
    \$\begingroup\$ It would be interesting (and worth mentioning) if 1e9 typechecks when used as BigInt, since scientific notation is usually treated as a float literal, not int, and typechecked as such. Hex is also a thing when used for large enough integers. \$\endgroup\$ – Bubbler Sep 8 '20 at 9:08
  • \$\begingroup\$ @Bubbler Yup, fixed it. Unfortunately, they only allow the same format as ordinary Ints and Doubles (afaik) \$\endgroup\$ – user Sep 8 '20 at 16:27
1
\$\begingroup\$

Optional braces

In match expressions, at least, you can save a byte by using indentation-based syntax.

a match
case b=>c
case d=>e

is 27 bytes, while the below code is 28.

a match{case b=>c case d=>e}

As a side note, match also gets special treatment when it comes to chaining. The following Scala 2 code:

("foo"match{case x=>x})match{case x=>x}

can now be written without the parentheses:

"foo"match{case x=>x}match{case x=>x}
\$\endgroup\$
1
\$\begingroup\$

Leave out new with creator applications

You can call constructors without using new (like Kotlin), treating all classes as if they have apply methods in their companions. This saves 4 bytes every time you instantiate something, since new Foo() becomes just Foo().

This also applies to givens (although you rarely need them for code golf):

given foo as Foo=new Foo() //bad
given foo as Foo=Foo()     //better
given foo as Foo           //great
\$\endgroup\$
0
\$\begingroup\$

Use match types for recursive functions that pattern match

Making a typealias with a match type is sometimes shorter than using a proper function. For example, take this implementation of the KI calculus (not an actual thing). The type doesn't need :Any, so you save 7 bytes in all (type is 1 byte more than def).

//A normal function
def r(t:Any):Any=t match{case(('K',x),y)=>r(x)case('I',x)=>r(x)case t=>t}
//With match types
type R[T]=T match{case(('K',x),y)=>R[x]case('I',x)=>R[x]case _=>T}

Admittedly, in this particular example, you could use auto-tupling, ->, pattern-matching function literals, etc. to make the def shorter, but this is just one case. When you're not dealing with tuples, or the return type is more complex than just Any, or you have multiple parameters, this tip becomes more useful.

\$\endgroup\$
0
\$\begingroup\$

New Control Syntax

In most cases, the new control syntax doesn't shorten code (and is actually more verbose), it comes in handy in for comprehensions. If your expression or pattern ends or starts with a parentheses or double quote, you can save a byte or two:

for((x,y,z)<-Seq((1,2,3),(3,4,5));y<-"foo")yield y+x  //Old-style syntax
for(x,y,z)<-Seq((1,2,3),(3,4,5));y<-"foo"yield y+x    //New control syntax

It's not as useful as some other things, like parameter untupling, but I often find myself using for comprehensions for function calls like f(foo) or Seq(1,2), which end in parentheses.

See it run in Scastie.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.