What can make scala more popular?

Why not?

We sort of changed our mind during Scala Days. We’ll look into using the compiler output from BSP to highlight errors as alternative to the builtin highlighting. This should help in cases where it own highlighting doesn’t work as expected. This will have drawbacks of course, such as losing the improved type error display

2 Likes

That’s a tradeoff, to be sure (I’m quite excited by the new work on error display), but here’s one upvote for y’all providing LSP as an option. My own system works fairly poorly in IDEA – presumably because it has a lot of complex shared dependencies, there is a strong tendency for me to get false positives and lots of red squigglies. (IDEA is especially bad at understanding my indirect underscore-imports: I see errors because it isn’t finding imported symbols, and unused-import highlights that are just plain wrong. I’ve been forced to change many imports just to make the IDE function properly.)

For most projects, I’m sure that IDEA does well (indeed, it works well for me at work, which is less of a massively-complex monolith), but I’m currently planning on shifting to Metals for my personal work because of this, and probably moving to VSCode as part of that. Having LSP support for Metals would help me keep using the same editor for work and home, which would be quite nice…

1 Like

why not both meme here :slight_smile:

It’s not, nor will it ever be, a crucial foundation, because these other languages took up the hot-spots.

I suspect that this very much depends on the organization that you work for. I work for a large blue chip networking company, mainly developing in C, and you can use whatever editor you like as long as you get the development work done.

Very few people choose to use Eclipse because they regard it as too bloated. I’ve used Eclipse extensively for C development, used Eclipse for Scala for a while, but then moved to the free version of Intellij because it seemed much better. I’ll probably try VS Code + Metals. Certainly the LSP seemly like the future.

1 Like

I think it is a bad vision.
IMHO: when some business company choose a language they always look up on real use cases.
It is very easy to assosiate scala with:

  • Functional
  • Parallel
  • Big Data
  • Reactive programming

It is enough to look up on recent news: news from the scala moocs

There is nothing like “if you need high performance you should avoid jvm”
It is ironic but it is written in the same messages:

I completely agree with it, for example we can look up at “Direct vs. non-direct buffers”
So I think if you really care about performance you should use right paradigm.
They can say do no use dynamic languages:

They can say, we should use access method by index, but it does not automatically mean we must use case classes.

Actually if we look at slick getting started
We can see

  // Insert some suppliers
  suppliers += (101, "Acme, Inc.",      "99 Market Street", "Groundsville", "CA", "95199"),
  suppliers += ( 49, "Superior Coffee", "1 Party Place",    "Mendocino",    "CA", "95460"),

Actually it should be array. And it is very inconvenient when we have more than 10 columns.

val q2 = for {
  c <- coffees if c.price < 9.0
  s <- suppliers if s.id === c.supID
} yield (c.name, s.name)

Usual our report can have more than 20 columns, and can return more than 100000 rows.
I just do not understand how such abstraction can be considered as good.

So it seems that scala is very good for big data, but only if you have less than 5 columns by row or static object oriented scheme.

IMHO: If you have dynamic rows with large amount of columns, scala has a lack of abstraction for:

Of course they can say scala is not the language for everything.
But I am sure if they want that scala gains more popularity.
Thay should look up at TIOBE Index - TIOBE

  • SQL 1.935%
  • PL/SQL 0.822%
  • Transact-SQL 0.569%
  • Scala 0.442%

It is very important at least at our company to have the ability to process comfortably rows with large amount of columns for big data.

Have a look at https://github.com/getquill/quill / https://getquill.io/

It has support for embedded case classes i.e. classes flattened during a SQL query:

case class Contact(phone: String, address: String) extends Embedded
case class Person(id: Int, name: String, contact: Contact)

ctx.run(query[Person])
// SELECT x.id, x.name, x.phone, x.address FROM Person x

Should work well for database tables with many columns.

We do not have any problem to map case classes.
We usually do not use native sql at all for orm oriented task.
It is very inconvinient to work with query like:

     with userRole as (
        select u.id as idUser
              ,u.susername as sUser
              ,pg.idacrole
          from btk_user u
          join btk_acusergrant g on u.id = g.iduser
          join btk_acprofilegrant pg on g.idacprofile = pg.idacprofile
         where coalesce(u.bnotactive,0) = 0 and coalesce(u.bIsTemplate,0) = 0
              #$svFlt
      )
      select tt.idUser
            ,tt.sUser
            ,tt.sAcObj
            ,tt.idAcObj
            ,tt.sAcObjBundle
            ,tt.idAcObjBundle
            ,tt.sAcObjItem
            ,tt.idAcObjItem
            ,string_agg(tt.sPrivTypeCode||'.'||tt.sPrivName,chr(10)) as cPriv
        from (
            select ur.idUser
	              ,ur.sUser
	              ,o.scode as sAcObj
	              ,o.id as idAcObj
	              ,b.scaption as sAcObjBundle
	              ,b.id as idAcObjBundle
	              ,oi.scode as sAcObjItem
	              ,oi.id as idAcObjItem
	              ,pt.sCode as sPrivTypeCode
	              ,ip.ssystemname as sPrivName
	              ,max(r.bhasaccess) as bhasaccess
	              ,coalesce(max(r.bdenied), 0) as bdenied
	          from userRole ur
	          join btk_acrolegrantreg r
	            on r.idacrole = ur.idacrole
	          join btk_acroleobjectgranttype gt
	            on r.idacroleobjectgranttype = gt.id
	           and gt.scode = 'Element'
	          join BTK_ACItemPrivilege ip
	            on r.idacitemprivilege = ip.id
	           and coalesce(ip.bold,0) = 0
	          join btk_acprivilegetype pt
	            on ip.idacprivilegetype = pt.id
	          join btk_acitem i
	            on ip.idacitem = i.id
	           and coalesce(i.bold,0) = 0
	          join btk_acobjectitem oi
	            on i.id = oi.idacitem
	           and r.idacobjectitem = oi.id
	           and coalesce(oi.bold,0) = 0
	          join btk_acobjectbundle b
	            on oi.idacobjectbundle = b.id
	            and coalesce(b.bold,0) = 0
	          join btk_acobject o
	            on b.idacobject = o.id
	           and coalesce(o.bold,0) = 0
	         group by ur.idUser,
	                  ur.sUser,
	                  o.id,
	                  b.id,
	                  oi.scode,
	                  oi.id,
	                  pt.scode,
	                  ip.ssystemname
        ) tt
      where tt.bdenied = 0
        and tt.bhasaccess = 1
      group by tt.idUser
	            ,tt.sUser
	            ,tt.sAcObj
	            ,tt.idAcObj
	            ,tt.sAcObjBundle
	            ,tt.idAcObjBundle
	            ,tt.sAcObjItem
	            ,tt.idAcObjItem

It is just inconvenient to create a case class on each query.

Just for example of some table

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<class xmlns="http://www.global-system.ru/xsd/global3-class-1.0" name="Bs_Goods" caption="ТМЦ"
       cardEditor.representation="HeaderCard" listEditor.selection="List" viewOptions.openCardType="mdi"
       group.type="multi" group.root="Goods" objectAttrCardType="group">
    <mixins>
        <mixin name="Gds_GdsSrv" isDpiManaged="true"/>
        <mixin name="Gds_ControlObject" isDpiManaged="true"/>
    </mixins>
    <attributes>
        <attr name="id" attribute-type="Long" caption="Идентификатор" order="-1" isMnemoCode="true" type="basic"
              isVisible="false"/>
        <attr name="idClass" attribute-type="Long" caption="Класс" order="-10" type="basic" isVisible="false"/>
        <attr name="gidSrc" attribute-type="Varchar" caption="Объект-источник" order="0" type="refAnyObject"
              isVisible="false"/>
        <attr name="sArticle" attribute-type="Varchar" caption="Ном.№" order="10" isMnemoCode="true" type="basic"
              isVisible="true" isRequired="true">
            <mnemoCodeColumn/>
        </attr>
        <attr name="sDesignation" attribute-type="Varchar" caption="Обозначение" order="15" type="basic"
              isVisible="false">
        </attr>
        <attr name="sDesignationOld" attribute-type="Varchar" caption="Обозначение (старое)" order="16" type="basic"
              isVisible="false">
        </attr>
        <attr name="sShortName" attribute-type="Varchar" caption="Короткое наименование" order="15" type="basic"/>
        <attr name="sName" attribute-type="Varchar" caption="Наименование" order="20" isHeadLine="true" type="basic"
              isVisible="true" isRequired="true">
            <headLineColumn length="512"/>
        </attr>
        <attr name="sExternalName" attribute-type="Varchar" caption="Наименование внешней системы" order="21" type="basic"
              isVisible="false" isRequired="false">
            <headLineColumn length="512"/>
        </attr>
        <attr name="sPartNumber" attribute-type="Varchar" caption="Артикул" order="30" type="basic" isVisible="true"/>
        <attr name="sNomName" attribute-type="Varchar" caption="Условное наименование" order="35" type="basic"/>
        <attr name="idMeasureItem" attribute-type="Long" caption="ЕИ" order="40" type="refObject"
              isVisible="true" ref.class="Msr_MeasureItem" isRequired="true" isObjectAttr="true"/>
        <attr name="idMeasureItem2" attribute-type="Long" caption="БЕИ2" order="135" type="refObject" isVisible="true"
              ref.class="Msr_MeasureItem"/>
        <attr name="nRoundPlaces2" attribute-type="Number" caption="Точность округления БЕИ2" order="136" type="basic"
              isVisible="true"/>
        <attr name="nConvertBaseToBase2" attribute-type="Number" caption="Коэффициент пересчета БЕИ в БЕИ2" order="138"
              type="basic" isVisible="true"/>
        <attr name="nRoundPlaces" attribute-type="Number" caption="Точность округления БЕИ" order="50" type="basic"
              isVisible="true" isRequired="true"/>
        <attr name="idMsrNorm" attribute-type="Long" caption="ЕИ Нормирования" order="136" type="refObject" isVisible="false"
              ref.class="Msr_MeasureItem" genMnemoCodeColumn="true"/>
        <attr name="nRoundPlacesNorm" attribute-type="Number" caption="Точность округления ЕИ Нормирования" order="137" type="basic"
              isVisible="true"/>
        <attr name="nConvertBaseToBaseNorm" attribute-type="Number" caption="Коэффициент пересчета БЕИ в ЕИ Нормирования" order="138"
              type="basic" isVisible="true"/>
        <attr name="bNotActive" attribute-type="Number" caption="Не используется" order="60" type="basic"
              defaultValue="0" isVisible="true" editorType="check">
            <booleanColumn/>
        </attr>
        <attr name="dExpiryDate" attribute-type="Date" caption="Дата окончания использования" order="70" type="basic"
              isVisible="true" editorType="calendar"/>
        <attr name="idState" attribute-type="Long" caption="Состояние" order="80" type="refObject" isVisible="true"
              ref.class="Btk_ClassState" isCopyInCopyObject="false"/>
        <attr name="idStateMC" attribute-type="Number" caption="Состояние" order="85" type="basic" isVisible="false" isCopyInCopyObject="false"/>
        <attr name="sDescription" attribute-type="Varchar" caption="Описание" order="90" type="basic" isVisible="true">
            <descriptionColumn/>
        </attr>
        <attr name="idGoodsAndServiceType" attribute-type="Long" caption="Тип ТМЦ" order="100" type="refObject"
              isVisible="true" ref.class="Gds_GoodsAndServiceType"/>
        <attr name="idObjectType" attribute-type="Long" caption="Тип ТМЦ" order="100" type="refObject" isVisible="true" ref.class="Btk_ObjectType"/>
        <attr name="idObjectTypeCons" attribute-type="Long" caption="Тип партии прихода" order="100" type="refObject" isVisible="true" ref.class="Btk_ObjectType"/>
        <attr name="sIndexNumber" attribute-type="Varchar" caption="Каталожный номер" order="110" type="basic"
              isVisible="true"/>
        <attr name="sCodeOsk" attribute-type="Varchar" caption="Код ОСК" order="115" isVisible="true"/>
        <attr name="sNameMaker" attribute-type="Varchar" caption="Наименование производителя" order="120" type="basic"
              isVisible="true"/>
        <attr name="sInternationalCaption" attribute-type="Varchar" caption="Международное название" order="130"
              type="basic" isVisible="true"/>
        <attr name="bIsSet" attribute-type="Number" caption="Является комплектом" order="140" type="basic"
              defaultValue="0" isVisible="true" editorType="check">
            <booleanColumn/>
        </attr>
        <attr name="bRossip" attribute-type="Number" caption="Россыпь" order="145" type="basic"
              defaultValue="0" isVisible="true" editorType="check">
            <booleanColumn/>
        </attr>
        <attr name="sGost" attribute-type="Varchar" caption="ГОСТ" order="150" type="basic" isVisible="true"/>
        <attr name="idGost" attribute-type="Long" caption="ГОСТ" order="160" type="refObject" isVisible="true"
              ref.class="Bs_Gost"/>
        <attr name="idGrade" attribute-type="Long" caption="Марка ТМЦ" order="180" type="refObject" isVisible="true"
              ref.class="Gds_Grade"/>
        <attr name="idSortamentType" attribute-type="Long" caption="Тип сортамента" order="190" isObjectAttr="true"
              type="refObject" isVisible="true" ref.class="Gds_SortamentType"/>
        <attr name="idAccessMethod" attribute-type="Long" caption="Метод доступа для партий" order="195" type="refObject" isVisible="true" ref.class="Gds_AccessMethod"/>
        <attr name="gid" attribute-type="Varchar" type="basic"/>
        <attr name="gidSpecification" attribute-type="Varchar" type="refAnyObject" caption="Спецификация" order="200"
              isVisible="false"/>
        <attr name="gidDefSuite" attribute-type="Varchar" type="refAnyObject" caption="Набор по умолчанию" order="210"
              isVisible="false" ref.class="Gds_Suite"/>
        <attr name="idSupplyDepartment" attribute-type="Long" caption="Группа доступа к номенклатуре" order="210"
              type="refObject" ref.class="Gds_SupplyDepartment" isVisible="false" isObjectAttr="true"/>
        <attr name="idABCClassifier" attribute-type="Long" caption="Классификатор  А,В,С" order="220"
              type="refObject" ref.class="Gds_ABCClassifier" isVisible="false" editorType="combo"/>
        <attr name="idTypeSize" attribute-type="Long" caption="Типоразмер" order="230" type="refObject" isVisible="false" ref.class="Gds_TypeSize"/>
        <attr name="bPurchase" attribute-type="Number" caption="Закупка" order="240" editorType="check" defaultValue="0" isVisible="false">
            <booleanColumn/>
        </attr>
        <attr name="sCodeITSI" attribute-type="Varchar" caption="Код ИТСИ" order="250" isVisible="false" isObjectAttr="true"/>
        <attr name="nWeight" attribute-type="Number" caption="Масса" order="260" isVisible="false" isObjectAttr="true"/>
        <attr name="nUdelnVes" attribute-type="Number" caption="Удельный вес" order="270" isVisible="false" isObjectAttr="true"/>
        <attr name="nIntDiameter" attribute-type="Number" caption="Посадочный диаметр" order="280" isVisible="false" isObjectAttr="true"/>
        <attr name="nDiameterOftheWire" attribute-type="Number" caption="Диаметр проволоки, мм" order="290" isVisible="false" isObjectAttr="true"/>
        <attr name="nWidth" attribute-type="Number" caption="Ширина, м" order="300" isVisible="false" isObjectAttr="true"/>
        <attr name="nHeight" attribute-type="Number" caption="Высота, м" order="310" isVisible="false" isObjectAttr="true"/>
        <attr name="nVolume" attribute-type="Number" caption="Объём , м3" order="320" isVisible="false" isObjectAttr="true"/>
        <attr name="nAvutilizationrate" attribute-type="Number" caption="Коэффициент использования" order="330" isVisible="false" isObjectAttr="true"/>
        <attr name="sOkpo" attribute-type="Varchar" caption="Код ОКП" order="340" isVisible="false"/>
        <attr name="nDelDays" attribute-type="Number" caption="Длительность поставки, кален. дн." order="350" isVisible="false" isObjectAttr="true"/>
        <attr name="nPurchDays" attribute-type="Number" caption="Длительность зак. процедур, кален. дн." order="360" isVisible="false" isObjectAttr="true"/>
        <attr name="nManufDays" attribute-type="Number" caption="Длительности изготовления, кален. дн." order="370" isVisible="false" isObjectAttr="true"/>
        <attr name="nResDays" attribute-type="Number" caption="Страховой период, кален. дн." order="380" isVisible="false" isObjectAttr="true"/>
        <attr name="nLength" attribute-type="Number" caption="Длина" order="390" isVisible="false" isObjectAttr="true"/>
        <attr name="nThickness" attribute-type="Number" caption="Толщина" order="400" isVisible="false" isObjectAttr="true"/>
        <attr name="nDiameter" attribute-type="Number" caption="Диаметр" order="410" isVisible="false" isObjectAttr="true"/>
        <attr name="idPurchaseDirection" attribute-type="Long" caption="Направление закупок" order="420"
              type="refObject" isVisible="true" ref.class="Bs_PurchaseDirection" isObjectAttr="true"/>
        <attr name="idControlType" attribute-type="Long" caption="Тип входного контроля" order="430"
              type="refObject" isVisible="true" ref.class="Gds_ControlType" isObjectAttr="true"/>
        <attr name="bNeedCheckIn" attribute-type="Number" caption="Требуется входной контроль" order="440" editorType="check" defaultValue="0" isVisible="true" isObjectAttr="true">
            <booleanColumn/>
        </attr>
        <attr name="bDeliveredInKit" attribute-type="Number" caption="Является комплектующей" order="450" editorType="check" defaultValue="0" isVisible="true" isObjectAttr="true">
            <booleanColumn/>
        </attr>
        <attr name="idOKVED2" attribute-type="Long" caption="Оквэд" order="460" type="refObject" isVisible="true"
              ref.class="Bs_OKVED2" isObjectAttr="true"/>
        <attr name="idBudgetItem" attribute-type="Long" caption="Статья бюджета ОСК" order="470"
              type="refObject" isVisible="false" ref.class="Bs_BudgetItem" isObjectAttr="true"/>
        <attr name="idKind" attribute-type="Long" caption="Вид номенклатуры" order="480"
              type="refObject" isVisible="false" ref.class="Gds_Kind" isObjectAttr="true"/>
        <attr name="idResDimSetting" attribute-type="Long" caption="Настройка разреза резерва" order="490"
              type="refObject" isVisible="false" ref.class="Gds_ResDimSetting" isObjectAttr="true"/>
    </attributes>
    <collections>
        <collection cascadeOnDelete="true" name="Bs_GoodMsrItem" ref.attr="idGoods"/>
        <collection cascadeOnDelete="true" name="Gds_ArticleContras" ref.attr="idGds" сopyWithMaster="false"/>
        <collection cascadeOnDelete="true" name="Gds_Suite" ref.attr="idGds"/>
        <collection cascadeOnDelete="true" name="Gds_GoodsBarCode" ref.attr="idGds"/>
        <collection cascadeOnDelete="true" name="Bs_GoodsSrc" ref.attr="idGds"/>
        <collection cascadeOnDelete="true" name="Gds_Analogues" ref.attr="idGds"/>
        <collection cascadeOnDelete="true" name="Gds_ContrasCode" ref.attr="idGds" сopyWithMaster="false"/>
        <collection cascadeOnDelete="true" name="Gds_ContrasDesignation" ref.attr="idGds" сopyWithMaster="false"/>
        <collection cascadeOnDelete="true" name="Gds_ContrasCaption" ref.attr="idGds" сopyWithMaster="false"/>
        <var-collection name="Gds_GdsSrvTaxRate" ref.attr="gidGdsSrv"/>
        <var-collection name="Btk_ObjectGroup" ref.attr="gidSrcObject" сopyWithMaster="false"/>
    </collections>
    <dbSchema>
        <indexes>
            <index name="idx_bs_goods_sname" version="0">
                CREATE INDEX IF NOT EXISTS idx_bs_goods_sname ON public.bs_goods (sname)
            </index>
        </indexes>
    </dbSchema>
</class>

If you don’t want full static typing then you can use scala.Dynamic to save on number of classes.

I’ll base my example on H2 database. Add "com.h2database" % "h2" % "1.4.199" to your build definition. Then following example will work:

import java.sql.{ResultSet, Types}

import org.h2.tools.SimpleResultSet

import scala.language.dynamics
import scala.reflect.ClassTag

class DynamicResultSet(underlying: ResultSet) extends Dynamic {
  import underlying._

  def selectDynamic[ColumnType: ClassTag](columnLabel: String): ColumnType = {
    val erasedClass = implicitly[ClassTag[ColumnType]].runtimeClass
    getObject(columnLabel, erasedClass.asInstanceOf[Class[ColumnType]])
  }

  def updateDynamic(columnLabel: String)(cellValue: Any): Unit =
    updateObject(columnLabel, cellValue)
}

object DynamicResultSet {
  implicit class RichResultSet(val self: ResultSet) extends AnyVal {
    def dyn: DynamicResultSet = new DynamicResultSet(self)
  }

  def main(args: Array[String]): Unit = {
    // row set setup
    val rs = new SimpleResultSet()
    rs.addColumn("name", Types.VARCHAR, 10, 0)
    rs.addColumn("size", Types.SMALLINT, 10, 0)
    rs.addRow("a", 8: Number)
    rs.setAutoClose(false)
    rs.beforeFirst()
    rs.next()
    // using row set through scala.Dynamic
    val drs = rs.dyn
    println(drs.name[String]) // prints: a
    println(drs.size[Integer]) // prints: 8
    drs.name = "Johnny"
    drs.name = ("John": AnyRef) // still works, even with imprecise static type
    drs.size = 2
    println(drs.name[String]) // prints: John
    println(drs.size[Integer]) // prints: 2
  }
}

Unfortunately we use native sql exactly in cases where performance is important. We can use dynamics we can use java we can not use scala.

What kind of dynamism you want to avoid? scala.Dynamic trait works in a simple way:

    drs.name = "Johnny"
    println(drs.name[String]) // prints: Johnny
    // is translated during compile-time (not run-time) to
    drs.updateDynamic("name")("Johnny")
    println(drs.selectDynamic[String]("name")) // prints: Johnny

Is simple method call too pricey?

1 Like

When we need filtering or sorting for example, access by key will appear in a profile report. It is annoying.

Is there anything (in Scala, Kotlin, Java, whatever) that fullfills your very obscure requirements? I haven’t seen a single attempt at putting field indexes into a type system. The closest one is HLists but they don’t store field names (so that probably rules them out), just heterogenous types in order. Also emulating field access by traversing such HList would be expensive.

1 Like

Could you explain what is the motivation of the question. Is it necessary that a feature would exist in another language? I remember the time when scala was the first. White box macros can help.

No, it’s not necessary, but so far there isn’t even a clear direction. You haven’t even shown a full theoretical example with your desired syntax and how would it desugar to a working example in conventional Scala.

I have an impression that if you try too hard to make super-flexible mechanism then you’ll end up with something costly anyway. Records in Dotty https://github.com/lampepfl/dotty-feature-requests/issues/8 look like plenty of class casts and megamorphic calls in addition to a new HList instance created for every new row.

But again, it’s hard to optimize for use case that is not fully known. Show the actual working code and tell where is the redundancy that you would want to avoid.

2 Likes

OK, it is clear. I will try to create more detailed topic later. It is not easy task for me. I just do not know whether something is difficult or not. The main idea:

  • it should be array or product after compilation in bytecode
  • Scala should allow to use name instead index in code
  • The dinamics is allowed for whole dataset instead of each row.
  • it should be very usefull in such library like slick :slight_smile:

See: Discussion about structural types(Flyweight pattern)

Is there anything (in Scala, Kotlin, Java, whatever) that fullfills your very obscure requirements? I haven’t seen a single attempt at putting field indexes into a type system.

Yeah, there is at least Haskell superrecord library - SuperRecord: Anonymous Records for Haskell that morphs morphs labels to indices. SML#, according to stackoverflow, uses implicits to pass indexes for polymorphic records - Why doesn't OCaml support record subtyping? - Stack Overflow
Also, so far all discussed implementations of structural types for Haskell in https://github.com/ghc-proposals/ghc-proposals/pull/180 are index-based, not hashmap-based.

However, all of the above are for row types without subtyping, I’m not aware of any implementation of index-based access for subtyped structural types.

1 Like

Thank you. Before these links I felt very confused. Now, I know, There are people which solve such tasks. :slight_smile: