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
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…
why not both meme here
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.
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:
- Scala programming language is 10 times faster than Python for data analysis and processing (Scala vs. Python for Apache Spark)
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:
- row processing
- Flyweight pattern
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?
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.
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.
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
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.
Thank you. Before these links I felt very confused. Now, I know, There are people which solve such tasks.